<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko">
	<id>https://clbiwiki.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Nxdsxn</id>
	<title>COASTLINE: BLACK ICE - 사용자 기여 [ko]</title>
	<link rel="self" type="application/atom+xml" href="https://clbiwiki.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Nxdsxn"/>
	<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php/%ED%8A%B9%EC%88%98:%EA%B8%B0%EC%97%AC/Nxdsxn"/>
	<updated>2026-06-03T09:10:57Z</updated>
	<subtitle>사용자 기여</subtitle>
	<generator>MediaWiki 1.41.5</generator>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2485</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2485"/>
		<updated>2026-06-03T09:06:36Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    var systemDocRawFetchToken = 0;&lt;br /&gt;
&lt;br /&gt;
    function cleanupLegacySystemDocCodeMutationsForShell() {&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codepane&#039;).forEach(function (pane) {&lt;br /&gt;
            var parent;&lt;br /&gt;
&lt;br /&gt;
            if (!pane || !pane.parentNode) return;&lt;br /&gt;
&lt;br /&gt;
            parent = pane.parentNode;&lt;br /&gt;
            while (pane.firstChild) {&lt;br /&gt;
                parent.insertBefore(pane.firstChild, pane);&lt;br /&gt;
            }&lt;br /&gt;
            parent.removeChild(pane);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codebox&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;style&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getSystemDocOutputForShell() {&lt;br /&gt;
        return document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function findSystemDocSourceNodeForShell() {&lt;br /&gt;
        var output = getSystemDocOutputForShell();&lt;br /&gt;
        var children;&lt;br /&gt;
        var preferred;&lt;br /&gt;
&lt;br /&gt;
        if (!output) return null;&lt;br /&gt;
&lt;br /&gt;
        children = Array.prototype.slice.call(output.children || [])&lt;br /&gt;
            .filter(function (el) {&lt;br /&gt;
                return el &amp;amp;&amp;amp; el.nodeType === 1 &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-doc-indicator-row&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-source-viewer&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    !el.classList.contains(&#039;catlinks&#039;) &amp;amp;&amp;amp;&lt;br /&gt;
                    (el.textContent || &#039;&#039;).trim().length &amp;gt; 200;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        preferred = children.filter(function (el) {&lt;br /&gt;
            return el.matches &amp;amp;&amp;amp; el.matches(&#039;.mw-highlight, .mw-code, pre&#039;);&lt;br /&gt;
        })[0];&lt;br /&gt;
&lt;br /&gt;
        return preferred || children.sort(function (a, b) {&lt;br /&gt;
            return (b.textContent || &#039;&#039;).trim().length - (a.textContent || &#039;&#039;).trim().length;&lt;br /&gt;
        })[0] || null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getSystemDocRawUrlForShell() {&lt;br /&gt;
        var title = mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.util &amp;amp;&amp;amp; typeof mw.util.getUrl === &#039;function&#039;) {&lt;br /&gt;
            return mw.util.getUrl(title, {&lt;br /&gt;
                action: &#039;raw&#039;,&lt;br /&gt;
                ctype: &#039;text/plain&#039;,&lt;br /&gt;
                _: String(Date.now())&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &#039;/index.php?title=&#039; + encodeURIComponent(title) + &#039;&amp;amp;action=raw&amp;amp;ctype=text/plain&amp;amp;_=&#039; + Date.now();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocSourceViewerForShell() {&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (viewer &amp;amp;&amp;amp; viewer.parentNode) {&lt;br /&gt;
            viewer.parentNode.removeChild(viewer);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-original-source-hidden&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-source-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensureSystemDocSourceViewerForShell() {&lt;br /&gt;
        var output = getSystemDocOutputForShell();&lt;br /&gt;
        var source;&lt;br /&gt;
        var viewer;&lt;br /&gt;
        var fallbackText;&lt;br /&gt;
&lt;br /&gt;
        if (!output || !isMediaWikiSystemAssetPageForShell()) return null;&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
&lt;br /&gt;
        source = findSystemDocSourceNodeForShell();&lt;br /&gt;
        if (!source) return null;&lt;br /&gt;
&lt;br /&gt;
        viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!viewer) {&lt;br /&gt;
            viewer = document.createElement(&#039;pre&#039;);&lt;br /&gt;
            viewer.id = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            viewer.className = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            output.appendChild(viewer);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fallbackText = source.textContent || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!viewer.textContent &amp;amp;&amp;amp; fallbackText) {&lt;br /&gt;
            viewer.textContent = fallbackText;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        source.classList.add(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
        source.setAttribute(&#039;data-clbi-system-source-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        source.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        return viewer;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocSourceViewerForShell() {&lt;br /&gt;
        var viewer;&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var token;&lt;br /&gt;
        var currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = String(mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell());&lt;br /&gt;
        viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        시스템 문서 뷰어가 이미 만들어져 있고 raw 원문도 로드된 상태라면&lt;br /&gt;
        다시 source 탐색/숨김/스타일 재적용을 하지 않는다.&lt;br /&gt;
        DevTools Elements 패널에서 body가 계속 파랗게 깜빡이던 원인은&lt;br /&gt;
        MutationObserver가 이 재적용을 반복해서 DOM attribute mutation을 만들었기 때문이다.&lt;br /&gt;
        */&lt;br /&gt;
        if (&lt;br /&gt;
            viewer &amp;amp;&amp;amp;&lt;br /&gt;
            viewer.getAttribute(&#039;data-clbi-raw-title&#039;) === pageName &amp;amp;&amp;amp;&lt;br /&gt;
            viewer.getAttribute(&#039;data-clbi-raw-loaded&#039;) === &#039;1&#039;&lt;br /&gt;
        ) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        viewer = ensureSystemDocSourceViewerForShell();&lt;br /&gt;
        if (!viewer) return;&lt;br /&gt;
&lt;br /&gt;
        currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
        viewer.setAttribute(&#039;data-clbi-raw-title&#039;, pageName);&lt;br /&gt;
        token = ++systemDocRawFetchToken;&lt;br /&gt;
&lt;br /&gt;
        fetch(getSystemDocRawUrlForShell(), { credentials: &#039;same-origin&#039; })&lt;br /&gt;
            .then(function (res) {&lt;br /&gt;
                if (!res.ok) throw new Error(&#039;raw fetch failed &#039; + res.status);&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function (text) {&lt;br /&gt;
                if (token !== systemDocRawFetchToken) return;&lt;br /&gt;
&lt;br /&gt;
                currentScrollTop = viewer.scrollTop || currentScrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
                if (text &amp;amp;&amp;amp; viewer.textContent !== text) {&lt;br /&gt;
                    viewer.textContent = text;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;1&#039;);&lt;br /&gt;
                viewer.scrollTop = currentScrollTop;&lt;br /&gt;
            })&lt;br /&gt;
            .catch(function () {&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;0&#039;);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!row) {&lt;br /&gt;
            row = document.createElement(&#039;div&#039;);&lt;br /&gt;
            row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
            row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
            box = document.createElement(&#039;div&#039;);&lt;br /&gt;
            box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
            meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
            label = document.createElement(&#039;span&#039;);&lt;br /&gt;
            label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
            label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
            type = document.createElement(&#039;span&#039;);&lt;br /&gt;
            type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
&lt;br /&gt;
            title = document.createElement(&#039;div&#039;);&lt;br /&gt;
            title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta.appendChild(label);&lt;br /&gt;
            meta.appendChild(type);&lt;br /&gt;
            box.appendChild(meta);&lt;br /&gt;
            box.appendChild(title);&lt;br /&gt;
            row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
            anchor = getSystemDocOutputForShell();&lt;br /&gt;
            main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
            if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
                anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
            } else if (main) {&lt;br /&gt;
                main.insertBefore(row, main.firstChild);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        type = row.querySelector(&#039;.clbi-system-doc-type&#039;);&lt;br /&gt;
        title = row.querySelector(&#039;.clbi-system-doc-title&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (type) type.textContent = ext;&lt;br /&gt;
        if (title) title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        renderSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            removeSystemDocIndicatorForShell();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function (mutations) {&lt;br /&gt;
            var i;&lt;br /&gt;
            var target;&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            시스템 CSS/JS 문서는 applyPageShellClasses()가 초기에 한 번&lt;br /&gt;
            인디케이터와 source viewer를 만든 뒤에는 MutationObserver가 다시&lt;br /&gt;
            같은 렌더링을 반복할 필요가 없다. 이 반복이 DevTools에서 body/요소가&lt;br /&gt;
            계속 플래시되는 직접 원인이다.&lt;br /&gt;
            SPA 전환 뒤의 처리는 loadPage()와 wikipage.content hook에서 따로 호출된다.&lt;br /&gt;
            */&lt;br /&gt;
            if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
                for (i = 0; i &amp;lt; mutations.length; i += 1) {&lt;br /&gt;
                    target = mutations[i] &amp;amp;&amp;amp; mutations[i].target;&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        target &amp;amp;&amp;amp;&lt;br /&gt;
                        target.nodeType === 1 &amp;amp;&amp;amp;&lt;br /&gt;
                        (&lt;br /&gt;
                            target.id === &#039;clbi-system-source-viewer&#039; ||&lt;br /&gt;
                            target.id === &#039;clbi-system-doc-indicator-row&#039; ||&lt;br /&gt;
                            (target.closest &amp;amp;&amp;amp; target.closest(&#039;#clbi-system-source-viewer, #clbi-system-doc-indicator-row&#039;))&lt;br /&gt;
                        )&lt;br /&gt;
                    ) {&lt;br /&gt;
                        return;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    document.getElementById(&#039;clbi-system-doc-indicator-row&#039;) &amp;amp;&amp;amp;&lt;br /&gt;
                    document.getElementById(&#039;clbi-system-source-viewer&#039;)&lt;br /&gt;
                ) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell,&lt;br /&gt;
        refreshSystemDocSourceViewer: renderSystemDocSourceViewerForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeClbiShellDomOrder() {&lt;br /&gt;
    var contentWrapper = document.querySelector(&#039;.content-wrapper&#039;);&lt;br /&gt;
    var topNav = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottomNav = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var canvas = document.getElementById(&#039;site-halftone-bg&#039;);&lt;br /&gt;
    var anchor;&lt;br /&gt;
&lt;br /&gt;
    if (!contentWrapper || !topNav || !bottomNav || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
    /*&lt;br /&gt;
    Some user environments keep a Liberty/skin placeholder before .content-wrapper.&lt;br /&gt;
    When nav/sidebar/content are inserted around that original position, the whole&lt;br /&gt;
    CLBI shell starts one viewport below the top, so users see only the background.&lt;br /&gt;
    The shell must be placed immediately after the fixed background canvas, not&lt;br /&gt;
    wherever Liberty originally left .content-wrapper.&lt;br /&gt;
    */&lt;br /&gt;
    anchor = canvas &amp;amp;&amp;amp; canvas.parentNode === document.body&lt;br /&gt;
        ? canvas.nextSibling&lt;br /&gt;
        : document.body.firstChild;&lt;br /&gt;
&lt;br /&gt;
    if (topNav.parentNode !== document.body || topNav.nextSibling !== contentWrapper) {&lt;br /&gt;
        document.body.insertBefore(topNav, anchor);&lt;br /&gt;
        document.body.insertBefore(contentWrapper, topNav.nextSibling);&lt;br /&gt;
        document.body.insertBefore(bottomNav, contentWrapper.nextSibling);&lt;br /&gt;
    } else if (bottomNav.previousSibling !== contentWrapper) {&lt;br /&gt;
        document.body.insertBefore(bottomNav, contentWrapper.nextSibling);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.body.classList.add(&#039;clbi-shell-ready&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
    normalizeClbiShellDomOrder();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    if (typeof scheduleAdaptiveLeftRecentItems === &#039;function&#039;) {&lt;br /&gt;
        scheduleAdaptiveLeftRecentItems();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.setTimeout(function () {&lt;br /&gt;
        updateClbiShellMetrics();&lt;br /&gt;
        if (typeof scheduleAdaptiveLeftRecentItems === &#039;function&#039;) {&lt;br /&gt;
            scheduleAdaptiveLeftRecentItems();&lt;br /&gt;
        }&lt;br /&gt;
    }, 0);&lt;br /&gt;
&lt;br /&gt;
    window.setTimeout(function () {&lt;br /&gt;
        updateClbiShellMetrics();&lt;br /&gt;
        if (typeof scheduleAdaptiveLeftRecentItems === &#039;function&#039;) {&lt;br /&gt;
            scheduleAdaptiveLeftRecentItems();&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    window.setTimeout(function () {&lt;br /&gt;
        updateClbiShellMetrics();&lt;br /&gt;
        if (typeof scheduleAdaptiveLeftRecentItems === &#039;function&#039;) {&lt;br /&gt;
            scheduleAdaptiveLeftRecentItems();&lt;br /&gt;
        }&lt;br /&gt;
    }, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            if (isNewsList &amp;amp;&amp;amp; typeof scheduleAdaptiveLeftRecentItems === &#039;function&#039;) {&lt;br /&gt;
                scheduleAdaptiveLeftRecentItems();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function updateAdaptiveLeftRecentItems() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-left-recent-list&#039;);&lt;br /&gt;
    var wrapper = document.querySelector(&#039;.content-wrapper&#039;);&lt;br /&gt;
    var newsBox;&lt;br /&gt;
    var items;&lt;br /&gt;
    var allVisibleBottom;&lt;br /&gt;
    var wrapperBottom;&lt;br /&gt;
    var followingHeight;&lt;br /&gt;
    var sibling;&lt;br /&gt;
    var listRect;&lt;br /&gt;
    var sample;&lt;br /&gt;
    var sampleRect;&lt;br /&gt;
    var sampleStyle;&lt;br /&gt;
    var itemStep;&lt;br /&gt;
    var available;&lt;br /&gt;
    var limit;&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    if (!list || !wrapper) return;&lt;br /&gt;
&lt;br /&gt;
    newsBox = list.closest(&#039;.clbi-left-news-box&#039;);&lt;br /&gt;
    items = Array.prototype.slice.call(list.querySelectorAll(&#039;.news-recent-item&#039;));&lt;br /&gt;
&lt;br /&gt;
    if (!newsBox || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
    /*&lt;br /&gt;
    기본 상태에서는 목록을 줄이지 않는다.&lt;br /&gt;
    먼저 전부 보이게 한 뒤, 뉴스 박스가 content-wrapper 하단을 넘는 경우에만&lt;br /&gt;
    최근 변경 항목을 줄인다.&lt;br /&gt;
    */&lt;br /&gt;
    items.forEach(function (item) {&lt;br /&gt;
        item.classList.remove(&#039;is-adaptive-hidden&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    wrapperBottom = Math.floor(wrapper.getBoundingClientRect().bottom);&lt;br /&gt;
&lt;br /&gt;
    followingHeight = 0;&lt;br /&gt;
    sibling = newsBox.nextElementSibling;&lt;br /&gt;
&lt;br /&gt;
    while (sibling) {&lt;br /&gt;
        if (sibling.offsetParent !== null) {&lt;br /&gt;
            followingHeight += Math.ceil(sibling.getBoundingClientRect().height || 0) + 8;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sibling = sibling.nextElementSibling;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    allVisibleBottom = Math.ceil(newsBox.getBoundingClientRect().bottom + followingHeight);&lt;br /&gt;
&lt;br /&gt;
    if (allVisibleBottom &amp;lt;= wrapperBottom) {&lt;br /&gt;
        list.setAttribute(&#039;data-adaptive-limit&#039;, String(items.length));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    listRect = list.getBoundingClientRect();&lt;br /&gt;
    sample = items[0];&lt;br /&gt;
    sampleRect = sample.getBoundingClientRect();&lt;br /&gt;
    sampleStyle = window.getComputedStyle(sample);&lt;br /&gt;
&lt;br /&gt;
    itemStep =&lt;br /&gt;
        Math.ceil(sampleRect.height || 36) +&lt;br /&gt;
        (parseFloat(sampleStyle.marginBottom || &#039;0&#039;) || 0);&lt;br /&gt;
&lt;br /&gt;
    if (!itemStep || itemStep &amp;lt; 1) itemStep = 38;&lt;br /&gt;
&lt;br /&gt;
    available = Math.floor(wrapperBottom - listRect.top - followingHeight);&lt;br /&gt;
&lt;br /&gt;
    /*&lt;br /&gt;
    CHANGELOG 영역과 RECENT CHANGES 타이틀은 유지하고, 최근 변경 항목만 줄인다.&lt;br /&gt;
    최소 1개는 남겨서 박스의 의미가 사라지지 않게 한다.&lt;br /&gt;
    */&lt;br /&gt;
    limit = Math.floor((available + 2) / itemStep);&lt;br /&gt;
    limit = Math.max(1, Math.min(items.length, limit));&lt;br /&gt;
&lt;br /&gt;
    list.setAttribute(&#039;data-adaptive-limit&#039;, String(limit));&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; items.length; i += 1) {&lt;br /&gt;
        items[i].classList.toggle(&#039;is-adaptive-hidden&#039;, i &amp;gt;= limit);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleAdaptiveLeftRecentItems() {&lt;br /&gt;
    window.requestAnimationFrame(function () {&lt;br /&gt;
        updateAdaptiveLeftRecentItems();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.setTimeout(updateAdaptiveLeftRecentItems, 80);&lt;br /&gt;
    window.setTimeout(updateAdaptiveLeftRecentItems, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        scheduleAdaptiveLeftRecentItems();&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    normalizeClbiShellDomOrder();&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                normalizeClbiShellDomOrder();&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2484</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2484"/>
		<updated>2026-06-03T09:06:29Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2-A. CLBI shell visibility safety&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
If a browser/user stylesheet or Liberty wrapper gives .content-wrapper a negative&lt;br /&gt;
stacking order, the generated shell can exist in the DOM while only the&lt;br /&gt;
background is visible.  The CLBI shell parts must sit above the halftone canvas.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
.content-wrapper,&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
z-index:1 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-shell-ready #clbi-top-nav-wrap,&lt;br /&gt;
body.clbi-shell-ready .content-wrapper,&lt;br /&gt;
body.clbi-shell-ready #clbi-bottom-nav-wrap {&lt;br /&gt;
visibility:visible !important;&lt;br /&gt;
opacity:1 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2-B. 세로 가변 셸 / 좌측 최근 변경 적응형&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상하단 네비는 고정된 조작 패널로 유지한다.&lt;br /&gt;
브라우저 세로 높이가 작아지면 가운데 content-wrapper만 줄어든다.&lt;br /&gt;
&lt;br /&gt;
좌측 뉴스 박스는 기본 상태에서 원래 내용 높이만 차지한다.&lt;br /&gt;
세로 공간이 부족할 때만 JS가 최근 변경 항목 수를 줄인다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
@supports (height: 100dvh) {&lt;br /&gt;
body {&lt;br /&gt;
height:100dvh !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
height:calc(100dvh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
max-height:calc(100dvh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
max-height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
align-self:flex-start !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
align-self:flex-start !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar .clbi-left-lang-box,&lt;br /&gt;
#clbi-left-sidebar .clbi-left-news-box {&lt;br /&gt;
flex:0 0 auto !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar .clbi-left-news-box {&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar .clbi-news-box {&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar .news-left-recent-feed {&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item.is-adaptive-hidden {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
CSS/JS 시스템 문서는 기본 제목을 숨기고 우상단 문서 표식과 raw source viewer를 사용한다.&lt;br /&gt;
&lt;br /&gt;
중요 구조:&lt;br /&gt;
- .liberty-content-main : 외곽 #1d1d1d 프레임&lt;br /&gt;
- #mw-content-text/.mw-body-content : MediaWiki가 끼워 넣는 중간 래퍼&lt;br /&gt;
- .mw-parser-output : 내부 #080808 우물&lt;br /&gt;
- #clbi-system-source-viewer : 우물 안에서 남은 높이를 차지하는 스크롤 패널&lt;br /&gt;
&lt;br /&gt;
이 중간 래퍼를 채우지 않으면 .mw-parser-output이 내용 높이로 접히고,&lt;br /&gt;
코드 영역이 얇은 줄처럼 보인다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page #mw-content-text,&lt;br /&gt;
body.clbi-system-doc-page .mw-body-content {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; :not(#clbi-system-source-viewer):not(#clbi-system-doc-indicator-row) {&lt;br /&gt;
flex:0 0 auto !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-original-source-hidden {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page #clbi-system-source-viewer {&lt;br /&gt;
display:block !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 0 !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
margin:8px 0 0 !important;&lt;br /&gt;
padding:8px 10px !important;&lt;br /&gt;
overflow:auto !important;&lt;br /&gt;
background:#f3f6f7 !important;&lt;br /&gt;
color:#111111 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
outline:none !important;&lt;br /&gt;
font-family:Consolas, Monaco, &#039;Courier New&#039;, monospace !important;&lt;br /&gt;
font-size:12px !important;&lt;br /&gt;
line-height:1.45 !important;&lt;br /&gt;
white-space:pre !important;&lt;br /&gt;
tab-size:4;&lt;br /&gt;
scrollbar-gutter:stable;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codepane,&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codebox {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:8px !important;&lt;br /&gt;
right:8px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 16px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
max-width:520px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:7px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:0.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
max-width:500px !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:24px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:0.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78) !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
word-break:normal !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2483</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2483"/>
		<updated>2026-06-03T09:02:49Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    var systemDocRawFetchToken = 0;&lt;br /&gt;
&lt;br /&gt;
    function cleanupLegacySystemDocCodeMutationsForShell() {&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codepane&#039;).forEach(function (pane) {&lt;br /&gt;
            var parent;&lt;br /&gt;
&lt;br /&gt;
            if (!pane || !pane.parentNode) return;&lt;br /&gt;
&lt;br /&gt;
            parent = pane.parentNode;&lt;br /&gt;
            while (pane.firstChild) {&lt;br /&gt;
                parent.insertBefore(pane.firstChild, pane);&lt;br /&gt;
            }&lt;br /&gt;
            parent.removeChild(pane);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codebox&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;style&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getSystemDocOutputForShell() {&lt;br /&gt;
        return document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function findSystemDocSourceNodeForShell() {&lt;br /&gt;
        var output = getSystemDocOutputForShell();&lt;br /&gt;
        var children;&lt;br /&gt;
        var preferred;&lt;br /&gt;
&lt;br /&gt;
        if (!output) return null;&lt;br /&gt;
&lt;br /&gt;
        children = Array.prototype.slice.call(output.children || [])&lt;br /&gt;
            .filter(function (el) {&lt;br /&gt;
                return el &amp;amp;&amp;amp; el.nodeType === 1 &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-doc-indicator-row&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-source-viewer&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    !el.classList.contains(&#039;catlinks&#039;) &amp;amp;&amp;amp;&lt;br /&gt;
                    (el.textContent || &#039;&#039;).trim().length &amp;gt; 200;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        preferred = children.filter(function (el) {&lt;br /&gt;
            return el.matches &amp;amp;&amp;amp; el.matches(&#039;.mw-highlight, .mw-code, pre&#039;);&lt;br /&gt;
        })[0];&lt;br /&gt;
&lt;br /&gt;
        return preferred || children.sort(function (a, b) {&lt;br /&gt;
            return (b.textContent || &#039;&#039;).trim().length - (a.textContent || &#039;&#039;).trim().length;&lt;br /&gt;
        })[0] || null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getSystemDocRawUrlForShell() {&lt;br /&gt;
        var title = mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.util &amp;amp;&amp;amp; typeof mw.util.getUrl === &#039;function&#039;) {&lt;br /&gt;
            return mw.util.getUrl(title, {&lt;br /&gt;
                action: &#039;raw&#039;,&lt;br /&gt;
                ctype: &#039;text/plain&#039;,&lt;br /&gt;
                _: String(Date.now())&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &#039;/index.php?title=&#039; + encodeURIComponent(title) + &#039;&amp;amp;action=raw&amp;amp;ctype=text/plain&amp;amp;_=&#039; + Date.now();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocSourceViewerForShell() {&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (viewer &amp;amp;&amp;amp; viewer.parentNode) {&lt;br /&gt;
            viewer.parentNode.removeChild(viewer);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-original-source-hidden&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-source-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensureSystemDocSourceViewerForShell() {&lt;br /&gt;
        var output = getSystemDocOutputForShell();&lt;br /&gt;
        var source;&lt;br /&gt;
        var viewer;&lt;br /&gt;
        var fallbackText;&lt;br /&gt;
&lt;br /&gt;
        if (!output || !isMediaWikiSystemAssetPageForShell()) return null;&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
&lt;br /&gt;
        source = findSystemDocSourceNodeForShell();&lt;br /&gt;
        if (!source) return null;&lt;br /&gt;
&lt;br /&gt;
        viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!viewer) {&lt;br /&gt;
            viewer = document.createElement(&#039;pre&#039;);&lt;br /&gt;
            viewer.id = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            viewer.className = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            output.appendChild(viewer);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fallbackText = source.textContent || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!viewer.textContent &amp;amp;&amp;amp; fallbackText) {&lt;br /&gt;
            viewer.textContent = fallbackText;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        source.classList.add(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
        source.setAttribute(&#039;data-clbi-system-source-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        source.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        return viewer;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocSourceViewerForShell() {&lt;br /&gt;
        var viewer;&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var token;&lt;br /&gt;
        var currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = String(mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell());&lt;br /&gt;
        viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        시스템 문서 뷰어가 이미 만들어져 있고 raw 원문도 로드된 상태라면&lt;br /&gt;
        다시 source 탐색/숨김/스타일 재적용을 하지 않는다.&lt;br /&gt;
        DevTools Elements 패널에서 body가 계속 파랗게 깜빡이던 원인은&lt;br /&gt;
        MutationObserver가 이 재적용을 반복해서 DOM attribute mutation을 만들었기 때문이다.&lt;br /&gt;
        */&lt;br /&gt;
        if (&lt;br /&gt;
            viewer &amp;amp;&amp;amp;&lt;br /&gt;
            viewer.getAttribute(&#039;data-clbi-raw-title&#039;) === pageName &amp;amp;&amp;amp;&lt;br /&gt;
            viewer.getAttribute(&#039;data-clbi-raw-loaded&#039;) === &#039;1&#039;&lt;br /&gt;
        ) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        viewer = ensureSystemDocSourceViewerForShell();&lt;br /&gt;
        if (!viewer) return;&lt;br /&gt;
&lt;br /&gt;
        currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
        viewer.setAttribute(&#039;data-clbi-raw-title&#039;, pageName);&lt;br /&gt;
        token = ++systemDocRawFetchToken;&lt;br /&gt;
&lt;br /&gt;
        fetch(getSystemDocRawUrlForShell(), { credentials: &#039;same-origin&#039; })&lt;br /&gt;
            .then(function (res) {&lt;br /&gt;
                if (!res.ok) throw new Error(&#039;raw fetch failed &#039; + res.status);&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function (text) {&lt;br /&gt;
                if (token !== systemDocRawFetchToken) return;&lt;br /&gt;
&lt;br /&gt;
                currentScrollTop = viewer.scrollTop || currentScrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
                if (text &amp;amp;&amp;amp; viewer.textContent !== text) {&lt;br /&gt;
                    viewer.textContent = text;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;1&#039;);&lt;br /&gt;
                viewer.scrollTop = currentScrollTop;&lt;br /&gt;
            })&lt;br /&gt;
            .catch(function () {&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;0&#039;);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!row) {&lt;br /&gt;
            row = document.createElement(&#039;div&#039;);&lt;br /&gt;
            row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
            row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
            box = document.createElement(&#039;div&#039;);&lt;br /&gt;
            box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
            meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
            label = document.createElement(&#039;span&#039;);&lt;br /&gt;
            label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
            label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
            type = document.createElement(&#039;span&#039;);&lt;br /&gt;
            type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
&lt;br /&gt;
            title = document.createElement(&#039;div&#039;);&lt;br /&gt;
            title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta.appendChild(label);&lt;br /&gt;
            meta.appendChild(type);&lt;br /&gt;
            box.appendChild(meta);&lt;br /&gt;
            box.appendChild(title);&lt;br /&gt;
            row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
            anchor = getSystemDocOutputForShell();&lt;br /&gt;
            main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
            if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
                anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
            } else if (main) {&lt;br /&gt;
                main.insertBefore(row, main.firstChild);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        type = row.querySelector(&#039;.clbi-system-doc-type&#039;);&lt;br /&gt;
        title = row.querySelector(&#039;.clbi-system-doc-title&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (type) type.textContent = ext;&lt;br /&gt;
        if (title) title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        renderSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            removeSystemDocIndicatorForShell();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function (mutations) {&lt;br /&gt;
            var i;&lt;br /&gt;
            var target;&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            시스템 CSS/JS 문서는 applyPageShellClasses()가 초기에 한 번&lt;br /&gt;
            인디케이터와 source viewer를 만든 뒤에는 MutationObserver가 다시&lt;br /&gt;
            같은 렌더링을 반복할 필요가 없다. 이 반복이 DevTools에서 body/요소가&lt;br /&gt;
            계속 플래시되는 직접 원인이다.&lt;br /&gt;
            SPA 전환 뒤의 처리는 loadPage()와 wikipage.content hook에서 따로 호출된다.&lt;br /&gt;
            */&lt;br /&gt;
            if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
                for (i = 0; i &amp;lt; mutations.length; i += 1) {&lt;br /&gt;
                    target = mutations[i] &amp;amp;&amp;amp; mutations[i].target;&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        target &amp;amp;&amp;amp;&lt;br /&gt;
                        target.nodeType === 1 &amp;amp;&amp;amp;&lt;br /&gt;
                        (&lt;br /&gt;
                            target.id === &#039;clbi-system-source-viewer&#039; ||&lt;br /&gt;
                            target.id === &#039;clbi-system-doc-indicator-row&#039; ||&lt;br /&gt;
                            (target.closest &amp;amp;&amp;amp; target.closest(&#039;#clbi-system-source-viewer, #clbi-system-doc-indicator-row&#039;))&lt;br /&gt;
                        )&lt;br /&gt;
                    ) {&lt;br /&gt;
                        return;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    document.getElementById(&#039;clbi-system-doc-indicator-row&#039;) &amp;amp;&amp;amp;&lt;br /&gt;
                    document.getElementById(&#039;clbi-system-source-viewer&#039;)&lt;br /&gt;
                ) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell,&lt;br /&gt;
        refreshSystemDocSourceViewer: renderSystemDocSourceViewerForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeClbiShellDomOrder() {&lt;br /&gt;
    var contentWrapper = document.querySelector(&#039;.content-wrapper&#039;);&lt;br /&gt;
    var topNav = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottomNav = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var canvas = document.getElementById(&#039;site-halftone-bg&#039;);&lt;br /&gt;
    var anchor;&lt;br /&gt;
&lt;br /&gt;
    if (!contentWrapper || !topNav || !bottomNav || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
    /*&lt;br /&gt;
    Some user environments keep a Liberty/skin placeholder before .content-wrapper.&lt;br /&gt;
    When nav/sidebar/content are inserted around that original position, the whole&lt;br /&gt;
    CLBI shell starts one viewport below the top, so users see only the background.&lt;br /&gt;
    The shell must be placed immediately after the fixed background canvas, not&lt;br /&gt;
    wherever Liberty originally left .content-wrapper.&lt;br /&gt;
    */&lt;br /&gt;
    anchor = canvas &amp;amp;&amp;amp; canvas.parentNode === document.body&lt;br /&gt;
        ? canvas.nextSibling&lt;br /&gt;
        : document.body.firstChild;&lt;br /&gt;
&lt;br /&gt;
    if (topNav.parentNode !== document.body || topNav.nextSibling !== contentWrapper) {&lt;br /&gt;
        document.body.insertBefore(topNav, anchor);&lt;br /&gt;
        document.body.insertBefore(contentWrapper, topNav.nextSibling);&lt;br /&gt;
        document.body.insertBefore(bottomNav, contentWrapper.nextSibling);&lt;br /&gt;
    } else if (bottomNav.previousSibling !== contentWrapper) {&lt;br /&gt;
        document.body.insertBefore(bottomNav, contentWrapper.nextSibling);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.body.classList.add(&#039;clbi-shell-ready&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
    normalizeClbiShellDomOrder();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    if (typeof scheduleAdaptiveLeftRecentItems === &#039;function&#039;) {&lt;br /&gt;
        scheduleAdaptiveLeftRecentItems();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.setTimeout(function () {&lt;br /&gt;
        updateClbiShellMetrics();&lt;br /&gt;
        if (typeof scheduleAdaptiveLeftRecentItems === &#039;function&#039;) {&lt;br /&gt;
            scheduleAdaptiveLeftRecentItems();&lt;br /&gt;
        }&lt;br /&gt;
    }, 0);&lt;br /&gt;
&lt;br /&gt;
    window.setTimeout(function () {&lt;br /&gt;
        updateClbiShellMetrics();&lt;br /&gt;
        if (typeof scheduleAdaptiveLeftRecentItems === &#039;function&#039;) {&lt;br /&gt;
            scheduleAdaptiveLeftRecentItems();&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    window.setTimeout(function () {&lt;br /&gt;
        updateClbiShellMetrics();&lt;br /&gt;
        if (typeof scheduleAdaptiveLeftRecentItems === &#039;function&#039;) {&lt;br /&gt;
            scheduleAdaptiveLeftRecentItems();&lt;br /&gt;
        }&lt;br /&gt;
    }, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            if (isNewsList &amp;amp;&amp;amp; typeof scheduleAdaptiveLeftRecentItems === &#039;function&#039;) {&lt;br /&gt;
                scheduleAdaptiveLeftRecentItems();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function updateAdaptiveLeftRecentItems() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-left-recent-list&#039;);&lt;br /&gt;
    var content;&lt;br /&gt;
    var items;&lt;br /&gt;
    var contentRect;&lt;br /&gt;
    var listRect;&lt;br /&gt;
    var available;&lt;br /&gt;
    var sample;&lt;br /&gt;
    var sampleRect;&lt;br /&gt;
    var sampleStyle;&lt;br /&gt;
    var itemStep;&lt;br /&gt;
    var limit;&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    content = list.closest(&#039;.clbi-news-box&#039;) || list.parentElement;&lt;br /&gt;
    items = Array.prototype.slice.call(list.querySelectorAll(&#039;.news-recent-item&#039;));&lt;br /&gt;
&lt;br /&gt;
    if (!content || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
    items.forEach(function (item) {&lt;br /&gt;
        item.classList.remove(&#039;is-adaptive-hidden&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    contentRect = content.getBoundingClientRect();&lt;br /&gt;
    listRect = list.getBoundingClientRect();&lt;br /&gt;
    available = Math.floor(contentRect.bottom - listRect.top);&lt;br /&gt;
&lt;br /&gt;
    if (!available || available &amp;lt; 24) {&lt;br /&gt;
        limit = 1;&lt;br /&gt;
    } else {&lt;br /&gt;
        sample = items[0];&lt;br /&gt;
        sampleRect = sample.getBoundingClientRect();&lt;br /&gt;
        sampleStyle = window.getComputedStyle(sample);&lt;br /&gt;
        itemStep =&lt;br /&gt;
            Math.ceil(sampleRect.height || 36) +&lt;br /&gt;
            (parseFloat(sampleStyle.marginBottom || &#039;0&#039;) || 0);&lt;br /&gt;
&lt;br /&gt;
        if (!itemStep || itemStep &amp;lt; 1) itemStep = 38;&lt;br /&gt;
&lt;br /&gt;
        limit = Math.floor((available + 2) / itemStep);&lt;br /&gt;
        limit = Math.max(1, Math.min(items.length, limit));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    list.setAttribute(&#039;data-adaptive-limit&#039;, String(limit));&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; items.length; i += 1) {&lt;br /&gt;
        items[i].classList.toggle(&#039;is-adaptive-hidden&#039;, i &amp;gt;= limit);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleAdaptiveLeftRecentItems() {&lt;br /&gt;
    window.requestAnimationFrame(function () {&lt;br /&gt;
        updateAdaptiveLeftRecentItems();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.setTimeout(updateAdaptiveLeftRecentItems, 80);&lt;br /&gt;
    window.setTimeout(updateAdaptiveLeftRecentItems, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        scheduleAdaptiveLeftRecentItems();&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    normalizeClbiShellDomOrder();&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                normalizeClbiShellDomOrder();&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2482</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2482"/>
		<updated>2026-06-03T09:02:32Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2-A. CLBI shell visibility safety&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
If a browser/user stylesheet or Liberty wrapper gives .content-wrapper a negative&lt;br /&gt;
stacking order, the generated shell can exist in the DOM while only the&lt;br /&gt;
background is visible.  The CLBI shell parts must sit above the halftone canvas.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
.content-wrapper,&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
z-index:1 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-shell-ready #clbi-top-nav-wrap,&lt;br /&gt;
body.clbi-shell-ready .content-wrapper,&lt;br /&gt;
body.clbi-shell-ready #clbi-bottom-nav-wrap {&lt;br /&gt;
visibility:visible !important;&lt;br /&gt;
opacity:1 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2-B. 세로 가변 셸 / 좌측 최근 변경 적응형&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상하단 네비는 고정된 조작 패널로 유지한다.&lt;br /&gt;
브라우저 세로 높이가 작아지면 가운데 content-wrapper만 줄어들고,&lt;br /&gt;
좌측 사이드바의 최근 변경 목록은 가능한 개수만 보여준다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
@supports (height: 100dvh) {&lt;br /&gt;
body {&lt;br /&gt;
height:100dvh !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
height:calc(100dvh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
max-height:calc(100dvh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
height:100% !important;&lt;br /&gt;
max-height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
align-self:stretch !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar .clbi-left-lang-box {&lt;br /&gt;
flex:0 0 auto !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar .clbi-left-news-box {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
min-height:148px !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar .clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
flex:0 0 auto !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar .clbi-left-news-box .clbi-news-box {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar .news-feed-title,&lt;br /&gt;
#clbi-left-sidebar .news-left-changelog-feed {&lt;br /&gt;
flex:0 0 auto !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar .news-left-recent-feed {&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item.is-adaptive-hidden {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
CSS/JS 시스템 문서는 기본 제목을 숨기고 우상단 문서 표식과 raw source viewer를 사용한다.&lt;br /&gt;
&lt;br /&gt;
중요 구조:&lt;br /&gt;
- .liberty-content-main : 외곽 #1d1d1d 프레임&lt;br /&gt;
- #mw-content-text/.mw-body-content : MediaWiki가 끼워 넣는 중간 래퍼&lt;br /&gt;
- .mw-parser-output : 내부 #080808 우물&lt;br /&gt;
- #clbi-system-source-viewer : 우물 안에서 남은 높이를 차지하는 스크롤 패널&lt;br /&gt;
&lt;br /&gt;
이 중간 래퍼를 채우지 않으면 .mw-parser-output이 내용 높이로 접히고,&lt;br /&gt;
코드 영역이 얇은 줄처럼 보인다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page #mw-content-text,&lt;br /&gt;
body.clbi-system-doc-page .mw-body-content {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; :not(#clbi-system-source-viewer):not(#clbi-system-doc-indicator-row) {&lt;br /&gt;
flex:0 0 auto !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-original-source-hidden {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page #clbi-system-source-viewer {&lt;br /&gt;
display:block !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 0 !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
margin:8px 0 0 !important;&lt;br /&gt;
padding:8px 10px !important;&lt;br /&gt;
overflow:auto !important;&lt;br /&gt;
background:#f3f6f7 !important;&lt;br /&gt;
color:#111111 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
outline:none !important;&lt;br /&gt;
font-family:Consolas, Monaco, &#039;Courier New&#039;, monospace !important;&lt;br /&gt;
font-size:12px !important;&lt;br /&gt;
line-height:1.45 !important;&lt;br /&gt;
white-space:pre !important;&lt;br /&gt;
tab-size:4;&lt;br /&gt;
scrollbar-gutter:stable;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codepane,&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codebox {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:8px !important;&lt;br /&gt;
right:8px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 16px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
max-width:520px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:7px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:0.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
max-width:500px !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:24px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:0.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78) !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
word-break:normal !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2481</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2481"/>
		<updated>2026-06-02T21:08:54Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    var systemDocRawFetchToken = 0;&lt;br /&gt;
&lt;br /&gt;
    function cleanupLegacySystemDocCodeMutationsForShell() {&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codepane&#039;).forEach(function (pane) {&lt;br /&gt;
            var parent;&lt;br /&gt;
&lt;br /&gt;
            if (!pane || !pane.parentNode) return;&lt;br /&gt;
&lt;br /&gt;
            parent = pane.parentNode;&lt;br /&gt;
            while (pane.firstChild) {&lt;br /&gt;
                parent.insertBefore(pane.firstChild, pane);&lt;br /&gt;
            }&lt;br /&gt;
            parent.removeChild(pane);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codebox&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;style&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getSystemDocOutputForShell() {&lt;br /&gt;
        return document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function findSystemDocSourceNodeForShell() {&lt;br /&gt;
        var output = getSystemDocOutputForShell();&lt;br /&gt;
        var children;&lt;br /&gt;
        var preferred;&lt;br /&gt;
&lt;br /&gt;
        if (!output) return null;&lt;br /&gt;
&lt;br /&gt;
        children = Array.prototype.slice.call(output.children || [])&lt;br /&gt;
            .filter(function (el) {&lt;br /&gt;
                return el &amp;amp;&amp;amp; el.nodeType === 1 &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-doc-indicator-row&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-source-viewer&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    !el.classList.contains(&#039;catlinks&#039;) &amp;amp;&amp;amp;&lt;br /&gt;
                    (el.textContent || &#039;&#039;).trim().length &amp;gt; 200;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        preferred = children.filter(function (el) {&lt;br /&gt;
            return el.matches &amp;amp;&amp;amp; el.matches(&#039;.mw-highlight, .mw-code, pre&#039;);&lt;br /&gt;
        })[0];&lt;br /&gt;
&lt;br /&gt;
        return preferred || children.sort(function (a, b) {&lt;br /&gt;
            return (b.textContent || &#039;&#039;).trim().length - (a.textContent || &#039;&#039;).trim().length;&lt;br /&gt;
        })[0] || null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getSystemDocRawUrlForShell() {&lt;br /&gt;
        var title = mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.util &amp;amp;&amp;amp; typeof mw.util.getUrl === &#039;function&#039;) {&lt;br /&gt;
            return mw.util.getUrl(title, {&lt;br /&gt;
                action: &#039;raw&#039;,&lt;br /&gt;
                ctype: &#039;text/plain&#039;,&lt;br /&gt;
                _: String(Date.now())&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &#039;/index.php?title=&#039; + encodeURIComponent(title) + &#039;&amp;amp;action=raw&amp;amp;ctype=text/plain&amp;amp;_=&#039; + Date.now();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocSourceViewerForShell() {&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (viewer &amp;amp;&amp;amp; viewer.parentNode) {&lt;br /&gt;
            viewer.parentNode.removeChild(viewer);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-original-source-hidden&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-source-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensureSystemDocSourceViewerForShell() {&lt;br /&gt;
        var output = getSystemDocOutputForShell();&lt;br /&gt;
        var source;&lt;br /&gt;
        var viewer;&lt;br /&gt;
        var fallbackText;&lt;br /&gt;
&lt;br /&gt;
        if (!output || !isMediaWikiSystemAssetPageForShell()) return null;&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
&lt;br /&gt;
        source = findSystemDocSourceNodeForShell();&lt;br /&gt;
        if (!source) return null;&lt;br /&gt;
&lt;br /&gt;
        viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!viewer) {&lt;br /&gt;
            viewer = document.createElement(&#039;pre&#039;);&lt;br /&gt;
            viewer.id = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            viewer.className = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            output.appendChild(viewer);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fallbackText = source.textContent || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!viewer.textContent &amp;amp;&amp;amp; fallbackText) {&lt;br /&gt;
            viewer.textContent = fallbackText;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        source.classList.add(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
        source.setAttribute(&#039;data-clbi-system-source-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        source.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        return viewer;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocSourceViewerForShell() {&lt;br /&gt;
        var viewer;&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var token;&lt;br /&gt;
        var currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = String(mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell());&lt;br /&gt;
        viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        시스템 문서 뷰어가 이미 만들어져 있고 raw 원문도 로드된 상태라면&lt;br /&gt;
        다시 source 탐색/숨김/스타일 재적용을 하지 않는다.&lt;br /&gt;
        DevTools Elements 패널에서 body가 계속 파랗게 깜빡이던 원인은&lt;br /&gt;
        MutationObserver가 이 재적용을 반복해서 DOM attribute mutation을 만들었기 때문이다.&lt;br /&gt;
        */&lt;br /&gt;
        if (&lt;br /&gt;
            viewer &amp;amp;&amp;amp;&lt;br /&gt;
            viewer.getAttribute(&#039;data-clbi-raw-title&#039;) === pageName &amp;amp;&amp;amp;&lt;br /&gt;
            viewer.getAttribute(&#039;data-clbi-raw-loaded&#039;) === &#039;1&#039;&lt;br /&gt;
        ) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        viewer = ensureSystemDocSourceViewerForShell();&lt;br /&gt;
        if (!viewer) return;&lt;br /&gt;
&lt;br /&gt;
        currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
        viewer.setAttribute(&#039;data-clbi-raw-title&#039;, pageName);&lt;br /&gt;
        token = ++systemDocRawFetchToken;&lt;br /&gt;
&lt;br /&gt;
        fetch(getSystemDocRawUrlForShell(), { credentials: &#039;same-origin&#039; })&lt;br /&gt;
            .then(function (res) {&lt;br /&gt;
                if (!res.ok) throw new Error(&#039;raw fetch failed &#039; + res.status);&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function (text) {&lt;br /&gt;
                if (token !== systemDocRawFetchToken) return;&lt;br /&gt;
&lt;br /&gt;
                currentScrollTop = viewer.scrollTop || currentScrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
                if (text &amp;amp;&amp;amp; viewer.textContent !== text) {&lt;br /&gt;
                    viewer.textContent = text;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;1&#039;);&lt;br /&gt;
                viewer.scrollTop = currentScrollTop;&lt;br /&gt;
            })&lt;br /&gt;
            .catch(function () {&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;0&#039;);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!row) {&lt;br /&gt;
            row = document.createElement(&#039;div&#039;);&lt;br /&gt;
            row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
            row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
            box = document.createElement(&#039;div&#039;);&lt;br /&gt;
            box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
            meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
            label = document.createElement(&#039;span&#039;);&lt;br /&gt;
            label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
            label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
            type = document.createElement(&#039;span&#039;);&lt;br /&gt;
            type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
&lt;br /&gt;
            title = document.createElement(&#039;div&#039;);&lt;br /&gt;
            title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta.appendChild(label);&lt;br /&gt;
            meta.appendChild(type);&lt;br /&gt;
            box.appendChild(meta);&lt;br /&gt;
            box.appendChild(title);&lt;br /&gt;
            row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
            anchor = getSystemDocOutputForShell();&lt;br /&gt;
            main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
            if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
                anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
            } else if (main) {&lt;br /&gt;
                main.insertBefore(row, main.firstChild);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        type = row.querySelector(&#039;.clbi-system-doc-type&#039;);&lt;br /&gt;
        title = row.querySelector(&#039;.clbi-system-doc-title&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (type) type.textContent = ext;&lt;br /&gt;
        if (title) title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        renderSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            removeSystemDocIndicatorForShell();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function (mutations) {&lt;br /&gt;
            var i;&lt;br /&gt;
            var target;&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            시스템 CSS/JS 문서는 applyPageShellClasses()가 초기에 한 번&lt;br /&gt;
            인디케이터와 source viewer를 만든 뒤에는 MutationObserver가 다시&lt;br /&gt;
            같은 렌더링을 반복할 필요가 없다. 이 반복이 DevTools에서 body/요소가&lt;br /&gt;
            계속 플래시되는 직접 원인이다.&lt;br /&gt;
            SPA 전환 뒤의 처리는 loadPage()와 wikipage.content hook에서 따로 호출된다.&lt;br /&gt;
            */&lt;br /&gt;
            if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
                for (i = 0; i &amp;lt; mutations.length; i += 1) {&lt;br /&gt;
                    target = mutations[i] &amp;amp;&amp;amp; mutations[i].target;&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        target &amp;amp;&amp;amp;&lt;br /&gt;
                        target.nodeType === 1 &amp;amp;&amp;amp;&lt;br /&gt;
                        (&lt;br /&gt;
                            target.id === &#039;clbi-system-source-viewer&#039; ||&lt;br /&gt;
                            target.id === &#039;clbi-system-doc-indicator-row&#039; ||&lt;br /&gt;
                            (target.closest &amp;amp;&amp;amp; target.closest(&#039;#clbi-system-source-viewer, #clbi-system-doc-indicator-row&#039;))&lt;br /&gt;
                        )&lt;br /&gt;
                    ) {&lt;br /&gt;
                        return;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    document.getElementById(&#039;clbi-system-doc-indicator-row&#039;) &amp;amp;&amp;amp;&lt;br /&gt;
                    document.getElementById(&#039;clbi-system-source-viewer&#039;)&lt;br /&gt;
                ) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell,&lt;br /&gt;
        refreshSystemDocSourceViewer: renderSystemDocSourceViewerForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2480</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2480"/>
		<updated>2026-06-02T21:05:19Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
CSS/JS 시스템 문서는 기본 제목을 숨기고 우상단 문서 표식과 raw source viewer를 사용한다.&lt;br /&gt;
&lt;br /&gt;
중요 구조:&lt;br /&gt;
- .liberty-content-main : 외곽 #1d1d1d 프레임&lt;br /&gt;
- #mw-content-text/.mw-body-content : MediaWiki가 끼워 넣는 중간 래퍼&lt;br /&gt;
- .mw-parser-output : 내부 #080808 우물&lt;br /&gt;
- #clbi-system-source-viewer : 우물 안에서 남은 높이를 차지하는 스크롤 패널&lt;br /&gt;
&lt;br /&gt;
이 중간 래퍼를 채우지 않으면 .mw-parser-output이 내용 높이로 접히고,&lt;br /&gt;
코드 영역이 얇은 줄처럼 보인다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page #mw-content-text,&lt;br /&gt;
body.clbi-system-doc-page .mw-body-content {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; :not(#clbi-system-source-viewer):not(#clbi-system-doc-indicator-row) {&lt;br /&gt;
flex:0 0 auto !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-original-source-hidden {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page #clbi-system-source-viewer {&lt;br /&gt;
display:block !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 0 !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
margin:8px 0 0 !important;&lt;br /&gt;
padding:8px 10px !important;&lt;br /&gt;
overflow:auto !important;&lt;br /&gt;
background:#f3f6f7 !important;&lt;br /&gt;
color:#111111 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
outline:none !important;&lt;br /&gt;
font-family:Consolas, Monaco, &#039;Courier New&#039;, monospace !important;&lt;br /&gt;
font-size:12px !important;&lt;br /&gt;
line-height:1.45 !important;&lt;br /&gt;
white-space:pre !important;&lt;br /&gt;
tab-size:4;&lt;br /&gt;
scrollbar-gutter:stable;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codepane,&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codebox {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:8px !important;&lt;br /&gt;
right:8px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 16px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
max-width:520px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:7px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:0.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
max-width:500px !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:24px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:0.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78) !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
word-break:normal !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2479</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2479"/>
		<updated>2026-06-02T21:01:45Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    var systemDocRawFetchToken = 0;&lt;br /&gt;
&lt;br /&gt;
    function cleanupLegacySystemDocCodeMutationsForShell() {&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codepane&#039;).forEach(function (pane) {&lt;br /&gt;
            var parent;&lt;br /&gt;
&lt;br /&gt;
            if (!pane || !pane.parentNode) return;&lt;br /&gt;
&lt;br /&gt;
            parent = pane.parentNode;&lt;br /&gt;
            while (pane.firstChild) {&lt;br /&gt;
                parent.insertBefore(pane.firstChild, pane);&lt;br /&gt;
            }&lt;br /&gt;
            parent.removeChild(pane);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codebox&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;style&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getSystemDocOutputForShell() {&lt;br /&gt;
        return document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function findSystemDocSourceNodeForShell() {&lt;br /&gt;
        var output = getSystemDocOutputForShell();&lt;br /&gt;
        var children;&lt;br /&gt;
        var preferred;&lt;br /&gt;
&lt;br /&gt;
        if (!output) return null;&lt;br /&gt;
&lt;br /&gt;
        children = Array.prototype.slice.call(output.children || [])&lt;br /&gt;
            .filter(function (el) {&lt;br /&gt;
                return el &amp;amp;&amp;amp; el.nodeType === 1 &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-doc-indicator-row&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-source-viewer&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    !el.classList.contains(&#039;catlinks&#039;) &amp;amp;&amp;amp;&lt;br /&gt;
                    (el.textContent || &#039;&#039;).trim().length &amp;gt; 200;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        preferred = children.filter(function (el) {&lt;br /&gt;
            return el.matches &amp;amp;&amp;amp; el.matches(&#039;.mw-highlight, .mw-code, pre&#039;);&lt;br /&gt;
        })[0];&lt;br /&gt;
&lt;br /&gt;
        return preferred || children.sort(function (a, b) {&lt;br /&gt;
            return (b.textContent || &#039;&#039;).trim().length - (a.textContent || &#039;&#039;).trim().length;&lt;br /&gt;
        })[0] || null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getSystemDocRawUrlForShell() {&lt;br /&gt;
        var title = mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.util &amp;amp;&amp;amp; typeof mw.util.getUrl === &#039;function&#039;) {&lt;br /&gt;
            return mw.util.getUrl(title, {&lt;br /&gt;
                action: &#039;raw&#039;,&lt;br /&gt;
                ctype: &#039;text/plain&#039;,&lt;br /&gt;
                _: String(Date.now())&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &#039;/index.php?title=&#039; + encodeURIComponent(title) + &#039;&amp;amp;action=raw&amp;amp;ctype=text/plain&amp;amp;_=&#039; + Date.now();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocSourceViewerForShell() {&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (viewer &amp;amp;&amp;amp; viewer.parentNode) {&lt;br /&gt;
            viewer.parentNode.removeChild(viewer);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-original-source-hidden&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-source-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensureSystemDocSourceViewerForShell() {&lt;br /&gt;
        var output = getSystemDocOutputForShell();&lt;br /&gt;
        var source;&lt;br /&gt;
        var viewer;&lt;br /&gt;
        var fallbackText;&lt;br /&gt;
&lt;br /&gt;
        if (!output || !isMediaWikiSystemAssetPageForShell()) return null;&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
&lt;br /&gt;
        source = findSystemDocSourceNodeForShell();&lt;br /&gt;
        if (!source) return null;&lt;br /&gt;
&lt;br /&gt;
        viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!viewer) {&lt;br /&gt;
            viewer = document.createElement(&#039;pre&#039;);&lt;br /&gt;
            viewer.id = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            viewer.className = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            output.appendChild(viewer);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fallbackText = source.textContent || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!viewer.textContent &amp;amp;&amp;amp; fallbackText) {&lt;br /&gt;
            viewer.textContent = fallbackText;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        source.classList.add(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
        source.setAttribute(&#039;data-clbi-system-source-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        source.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        return viewer;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocSourceViewerForShell() {&lt;br /&gt;
        var viewer;&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var token;&lt;br /&gt;
        var currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        viewer = ensureSystemDocSourceViewerForShell();&lt;br /&gt;
        if (!viewer) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = String(mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell());&lt;br /&gt;
&lt;br /&gt;
        if (viewer.getAttribute(&#039;data-clbi-raw-title&#039;) === pageName &amp;amp;&amp;amp; viewer.getAttribute(&#039;data-clbi-raw-loaded&#039;) === &#039;1&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
        viewer.setAttribute(&#039;data-clbi-raw-title&#039;, pageName);&lt;br /&gt;
        token = ++systemDocRawFetchToken;&lt;br /&gt;
&lt;br /&gt;
        fetch(getSystemDocRawUrlForShell(), { credentials: &#039;same-origin&#039; })&lt;br /&gt;
            .then(function (res) {&lt;br /&gt;
                if (!res.ok) throw new Error(&#039;raw fetch failed &#039; + res.status);&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function (text) {&lt;br /&gt;
                if (token !== systemDocRawFetchToken) return;&lt;br /&gt;
&lt;br /&gt;
                currentScrollTop = viewer.scrollTop || currentScrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
                if (text &amp;amp;&amp;amp; viewer.textContent !== text) {&lt;br /&gt;
                    viewer.textContent = text;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;1&#039;);&lt;br /&gt;
                viewer.scrollTop = currentScrollTop;&lt;br /&gt;
            })&lt;br /&gt;
            .catch(function () {&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;0&#039;);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!row) {&lt;br /&gt;
            row = document.createElement(&#039;div&#039;);&lt;br /&gt;
            row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
            row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
            box = document.createElement(&#039;div&#039;);&lt;br /&gt;
            box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
            meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
            label = document.createElement(&#039;span&#039;);&lt;br /&gt;
            label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
            label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
            type = document.createElement(&#039;span&#039;);&lt;br /&gt;
            type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
&lt;br /&gt;
            title = document.createElement(&#039;div&#039;);&lt;br /&gt;
            title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta.appendChild(label);&lt;br /&gt;
            meta.appendChild(type);&lt;br /&gt;
            box.appendChild(meta);&lt;br /&gt;
            box.appendChild(title);&lt;br /&gt;
            row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
            anchor = getSystemDocOutputForShell();&lt;br /&gt;
            main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
            if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
                anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
            } else if (main) {&lt;br /&gt;
                main.insertBefore(row, main.firstChild);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        type = row.querySelector(&#039;.clbi-system-doc-type&#039;);&lt;br /&gt;
        title = row.querySelector(&#039;.clbi-system-doc-title&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (type) type.textContent = ext;&lt;br /&gt;
        if (title) title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        renderSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            removeSystemDocIndicatorForShell();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell,&lt;br /&gt;
        refreshSystemDocSourceViewer: renderSystemDocSourceViewerForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2478</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2478"/>
		<updated>2026-06-02T21:01:38Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
CSS/JS 시스템 문서는 기본 제목을 숨기고 우상단 문서 표식과 raw source viewer를 사용한다.&lt;br /&gt;
source viewer는 .mw-parser-output 안에서 absolute inset:8px로 배치되어&lt;br /&gt;
우물의 상하좌우 8px 마감을 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-original-source-hidden {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page #clbi-system-source-viewer {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
left:8px !important;&lt;br /&gt;
right:8px !important;&lt;br /&gt;
top:8px !important;&lt;br /&gt;
bottom:8px !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px 10px !important;&lt;br /&gt;
overflow:auto !important;&lt;br /&gt;
background:#f3f6f7 !important;&lt;br /&gt;
color:#111111 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
outline:none !important;&lt;br /&gt;
font-family:Consolas, Monaco, &#039;Courier New&#039;, monospace !important;&lt;br /&gt;
font-size:12px !important;&lt;br /&gt;
line-height:1.45 !important;&lt;br /&gt;
white-space:pre !important;&lt;br /&gt;
tab-size:4;&lt;br /&gt;
scrollbar-gutter:stable;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codepane,&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codebox {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:8px !important;&lt;br /&gt;
right:8px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 16px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
max-width:520px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:7px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:0.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
max-width:500px !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:24px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:0.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78) !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
word-break:normal !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2477</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2477"/>
		<updated>2026-06-02T20:55:42Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    function cleanupSystemDocViewerResidueForShell() {&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (viewer &amp;amp;&amp;amp; viewer.parentNode) {&lt;br /&gt;
            viewer.parentNode.removeChild(viewer);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codepane&#039;).forEach(function (pane) {&lt;br /&gt;
            var parent;&lt;br /&gt;
&lt;br /&gt;
            if (!pane || !pane.parentNode) return;&lt;br /&gt;
&lt;br /&gt;
            parent = pane.parentNode;&lt;br /&gt;
            while (pane.firstChild) {&lt;br /&gt;
                parent.insertBefore(pane.firstChild, pane);&lt;br /&gt;
            }&lt;br /&gt;
            parent.removeChild(pane);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codebox, .clbi-system-original-source-hidden&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-source-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cleanupSystemDocViewerResidueForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        cleanupSystemDocViewerResidueForShell();&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!row) {&lt;br /&gt;
            row = document.createElement(&#039;div&#039;);&lt;br /&gt;
            row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
            row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
            box = document.createElement(&#039;div&#039;);&lt;br /&gt;
            box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
            meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
            label = document.createElement(&#039;span&#039;);&lt;br /&gt;
            label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
            label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
            type = document.createElement(&#039;span&#039;);&lt;br /&gt;
            type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
&lt;br /&gt;
            title = document.createElement(&#039;div&#039;);&lt;br /&gt;
            title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta.appendChild(label);&lt;br /&gt;
            meta.appendChild(type);&lt;br /&gt;
            box.appendChild(meta);&lt;br /&gt;
            box.appendChild(title);&lt;br /&gt;
            row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
            anchor = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
            main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
            if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
                anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
            } else if (main) {&lt;br /&gt;
                main.insertBefore(row, main.firstChild);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        type = row.querySelector(&#039;.clbi-system-doc-type&#039;);&lt;br /&gt;
        title = row.querySelector(&#039;.clbi-system-doc-title&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (type) type.textContent = ext;&lt;br /&gt;
        if (title) title.textContent = pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            removeSystemDocIndicatorForShell();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell,&lt;br /&gt;
        cleanupSystemDocViewerResidue: cleanupSystemDocViewerResidueForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2476</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2476"/>
		<updated>2026-06-02T20:55:34Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
시스템 CSS/JS 문서는 기본 제목을 숨기고 우상단 문서 표식만 띄운다.&lt;br /&gt;
코드 본문은 MediaWiki 원본 .mw-highlight를 유지하고,&lt;br /&gt;
.mw-parser-output 내부 우물 자체가 스크롤을 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow:auto !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
scrollbar-gutter:stable;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; .mw-highlight,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; .mw-code,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; pre {&lt;br /&gt;
display:block !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
min-width:100% !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
background:#f3f6f7 !important;&lt;br /&gt;
color:#111111 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; .mw-highlight pre,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; .mw-code pre,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; pre {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
white-space:pre !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page #clbi-system-source-viewer,&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codepane {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:8px !important;&lt;br /&gt;
right:8px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 16px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
max-width:520px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:7px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:0.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
max-width:500px !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:24px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:0.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78) !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
word-break:normal !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2475</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2475"/>
		<updated>2026-06-02T20:52:05Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    var systemDocRawFetchToken = 0;&lt;br /&gt;
&lt;br /&gt;
    function cleanupLegacySystemDocCodeMutationsForShell() {&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codepane&#039;).forEach(function (pane) {&lt;br /&gt;
            var parent;&lt;br /&gt;
&lt;br /&gt;
            if (!pane || !pane.parentNode) return;&lt;br /&gt;
&lt;br /&gt;
            parent = pane.parentNode;&lt;br /&gt;
            while (pane.firstChild) {&lt;br /&gt;
                parent.insertBefore(pane.firstChild, pane);&lt;br /&gt;
            }&lt;br /&gt;
            parent.removeChild(pane);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codebox&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;style&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getSystemDocOutputForShell() {&lt;br /&gt;
        return document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function findSystemDocSourceNodeForShell() {&lt;br /&gt;
        var output = getSystemDocOutputForShell();&lt;br /&gt;
        var children;&lt;br /&gt;
        var preferred;&lt;br /&gt;
&lt;br /&gt;
        if (!output) return null;&lt;br /&gt;
&lt;br /&gt;
        children = Array.prototype.slice.call(output.children || [])&lt;br /&gt;
            .filter(function (el) {&lt;br /&gt;
                return el &amp;amp;&amp;amp; el.nodeType === 1 &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-doc-indicator-row&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-source-viewer&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    !el.classList.contains(&#039;catlinks&#039;) &amp;amp;&amp;amp;&lt;br /&gt;
                    (el.textContent || &#039;&#039;).trim().length &amp;gt; 200;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        preferred = children.filter(function (el) {&lt;br /&gt;
            return el.matches &amp;amp;&amp;amp; el.matches(&#039;.mw-highlight, .mw-code, pre&#039;);&lt;br /&gt;
        })[0];&lt;br /&gt;
&lt;br /&gt;
        return preferred || children.sort(function (a, b) {&lt;br /&gt;
            return (b.textContent || &#039;&#039;).trim().length - (a.textContent || &#039;&#039;).trim().length;&lt;br /&gt;
        })[0] || null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getSystemDocRawUrlForShell() {&lt;br /&gt;
        var title = mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.util &amp;amp;&amp;amp; typeof mw.util.getUrl === &#039;function&#039;) {&lt;br /&gt;
            return mw.util.getUrl(title, {&lt;br /&gt;
                action: &#039;raw&#039;,&lt;br /&gt;
                ctype: &#039;text/plain&#039;,&lt;br /&gt;
                _: String(Date.now())&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &#039;/index.php?title=&#039; + encodeURIComponent(title) + &#039;&amp;amp;action=raw&amp;amp;ctype=text/plain&amp;amp;_=&#039; + Date.now();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocSourceViewerForShell() {&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (viewer &amp;amp;&amp;amp; viewer.parentNode) {&lt;br /&gt;
            viewer.parentNode.removeChild(viewer);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-original-source-hidden&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-source-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensureSystemDocSourceViewerForShell() {&lt;br /&gt;
        var output = getSystemDocOutputForShell();&lt;br /&gt;
        var source;&lt;br /&gt;
        var viewer;&lt;br /&gt;
        var fallbackText;&lt;br /&gt;
&lt;br /&gt;
        if (!output || !isMediaWikiSystemAssetPageForShell()) return null;&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
&lt;br /&gt;
        source = findSystemDocSourceNodeForShell();&lt;br /&gt;
        if (!source) return null;&lt;br /&gt;
&lt;br /&gt;
        viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!viewer) {&lt;br /&gt;
            viewer = document.createElement(&#039;pre&#039;);&lt;br /&gt;
            viewer.id = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            viewer.className = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            output.insertBefore(viewer, source);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fallbackText = source.textContent || &#039;&#039;;&lt;br /&gt;
        if (!viewer.textContent &amp;amp;&amp;amp; fallbackText) {&lt;br /&gt;
            viewer.textContent = fallbackText;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        source.classList.add(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
        source.setAttribute(&#039;data-clbi-system-source-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        source.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        return viewer;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocSourceViewerForShell() {&lt;br /&gt;
        var viewer;&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var token;&lt;br /&gt;
        var currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        viewer = ensureSystemDocSourceViewerForShell();&lt;br /&gt;
        if (!viewer) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = String(mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell());&lt;br /&gt;
&lt;br /&gt;
        if (viewer.getAttribute(&#039;data-clbi-raw-title&#039;) === pageName &amp;amp;&amp;amp; viewer.getAttribute(&#039;data-clbi-raw-loaded&#039;) === &#039;1&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
        viewer.setAttribute(&#039;data-clbi-raw-title&#039;, pageName);&lt;br /&gt;
        token = ++systemDocRawFetchToken;&lt;br /&gt;
&lt;br /&gt;
        fetch(getSystemDocRawUrlForShell(), { credentials: &#039;same-origin&#039; })&lt;br /&gt;
            .then(function (res) {&lt;br /&gt;
                if (!res.ok) throw new Error(&#039;raw fetch failed &#039; + res.status);&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function (text) {&lt;br /&gt;
                if (token !== systemDocRawFetchToken) return;&lt;br /&gt;
&lt;br /&gt;
                currentScrollTop = viewer.scrollTop || currentScrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
                if (text &amp;amp;&amp;amp; viewer.textContent !== text) {&lt;br /&gt;
                    viewer.textContent = text;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;1&#039;);&lt;br /&gt;
                viewer.scrollTop = currentScrollTop;&lt;br /&gt;
            })&lt;br /&gt;
            .catch(function () {&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;0&#039;);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!row) {&lt;br /&gt;
            row = document.createElement(&#039;div&#039;);&lt;br /&gt;
            row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
            row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
            box = document.createElement(&#039;div&#039;);&lt;br /&gt;
            box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
            meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
            label = document.createElement(&#039;span&#039;);&lt;br /&gt;
            label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
            label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
            type = document.createElement(&#039;span&#039;);&lt;br /&gt;
            type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
&lt;br /&gt;
            title = document.createElement(&#039;div&#039;);&lt;br /&gt;
            title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta.appendChild(label);&lt;br /&gt;
            meta.appendChild(type);&lt;br /&gt;
            box.appendChild(meta);&lt;br /&gt;
            box.appendChild(title);&lt;br /&gt;
            row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
            anchor = getSystemDocOutputForShell();&lt;br /&gt;
            main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
            if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
                anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
            } else if (main) {&lt;br /&gt;
                main.insertBefore(row, main.firstChild);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        type = row.querySelector(&#039;.clbi-system-doc-type&#039;);&lt;br /&gt;
        title = row.querySelector(&#039;.clbi-system-doc-title&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (type) type.textContent = ext;&lt;br /&gt;
        if (title) title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        renderSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            removeSystemDocIndicatorForShell();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;resize&#039;, function () {&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            window.setTimeout(applySystemDocSourceViewerLayoutForShell, 0);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        renderSystemDocSourceViewer: renderSystemDocSourceViewerForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell,&lt;br /&gt;
        refreshSystemDocSourceViewer: renderSystemDocSourceViewerForShell,&lt;br /&gt;
        layoutSystemDocSourceViewer: applySystemDocSourceViewerLayoutForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2474</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2474"/>
		<updated>2026-06-02T20:51:55Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
CSS/JS 시스템 문서는 기본 제목을 숨기고, 우상단 문서 표식과 raw source viewer를 사용한다.&lt;br /&gt;
- .liberty-content-main: 외곽 프레임&lt;br /&gt;
- .mw-parser-output: 내부 우물&lt;br /&gt;
- #clbi-system-source-viewer: 내부 우물 안에서 남은 높이를 차지하는 스크롤 패널&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; :not(#clbi-system-source-viewer):not(#clbi-system-doc-indicator-row) {&lt;br /&gt;
flex:0 0 auto !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-original-source-hidden {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page #clbi-system-source-viewer {&lt;br /&gt;
display:block !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 0 !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
margin:8px 0 0 !important;&lt;br /&gt;
padding:8px 10px !important;&lt;br /&gt;
overflow:auto !important;&lt;br /&gt;
background:#f3f6f7 !important;&lt;br /&gt;
color:#111111 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
outline:none !important;&lt;br /&gt;
font-family:Consolas, Monaco, &#039;Courier New&#039;, monospace !important;&lt;br /&gt;
font-size:12px !important;&lt;br /&gt;
line-height:1.45 !important;&lt;br /&gt;
white-space:pre !important;&lt;br /&gt;
tab-size:4;&lt;br /&gt;
scrollbar-gutter:stable;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:8px !important;&lt;br /&gt;
right:8px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 16px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
max-width:520px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:7px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:0.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
max-width:500px !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:24px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:0.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78) !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
word-break:normal !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2473</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2473"/>
		<updated>2026-06-02T20:45:34Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    var systemDocRawFetchToken = 0;&lt;br /&gt;
    var systemDocRendering = false;&lt;br /&gt;
&lt;br /&gt;
    function cleanupLegacySystemDocCodeMutationsForShell() {&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codepane&#039;).forEach(function (pane) {&lt;br /&gt;
            var parent;&lt;br /&gt;
            if (!pane || !pane.parentNode) return;&lt;br /&gt;
&lt;br /&gt;
            parent = pane.parentNode;&lt;br /&gt;
            while (pane.firstChild) {&lt;br /&gt;
                parent.insertBefore(pane.firstChild, pane);&lt;br /&gt;
            }&lt;br /&gt;
            parent.removeChild(pane);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codebox&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;box-sizing&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;flex&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;max-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;background&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;color&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function findSystemDocSourceNodeForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var children;&lt;br /&gt;
        var preferred;&lt;br /&gt;
&lt;br /&gt;
        if (!output) return null;&lt;br /&gt;
&lt;br /&gt;
        children = Array.prototype.slice.call(output.children || [])&lt;br /&gt;
            .filter(function (el) {&lt;br /&gt;
                return el &amp;amp;&amp;amp; el.nodeType === 1 &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-doc-indicator-row&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-source-viewer&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    !el.classList.contains(&#039;catlinks&#039;) &amp;amp;&amp;amp;&lt;br /&gt;
                    (el.textContent || &#039;&#039;).trim().length &amp;gt; 200;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        preferred = children.filter(function (el) {&lt;br /&gt;
            return el.matches &amp;amp;&amp;amp; el.matches(&#039;.mw-highlight, .mw-code, pre&#039;);&lt;br /&gt;
        })[0];&lt;br /&gt;
&lt;br /&gt;
        return preferred || children.sort(function (a, b) {&lt;br /&gt;
            return (b.textContent || &#039;&#039;).trim().length - (a.textContent || &#039;&#039;).trim().length;&lt;br /&gt;
        })[0] || null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getSystemDocRawUrlForShell() {&lt;br /&gt;
        var title = mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.util &amp;amp;&amp;amp; typeof mw.util.getUrl === &#039;function&#039;) {&lt;br /&gt;
            return mw.util.getUrl(title, {&lt;br /&gt;
                action: &#039;raw&#039;,&lt;br /&gt;
                ctype: &#039;text/plain&#039;,&lt;br /&gt;
                _: String(Date.now())&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &#039;/index.php?title=&#039; + encodeURIComponent(title) + &#039;&amp;amp;action=raw&amp;amp;ctype=text/plain&amp;amp;_=&#039; + Date.now();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocSourceViewerForShell() {&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (viewer &amp;amp;&amp;amp; viewer.parentNode) {&lt;br /&gt;
            viewer.parentNode.removeChild(viewer);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-original-source-hidden&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-source-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocSourceViewerForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var source;&lt;br /&gt;
        var viewer;&lt;br /&gt;
        var fallbackText;&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var token;&lt;br /&gt;
        var currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (!output || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
&lt;br /&gt;
        source = findSystemDocSourceNodeForShell();&lt;br /&gt;
        if (!source) return;&lt;br /&gt;
&lt;br /&gt;
        viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
        fallbackText = source.textContent || &#039;&#039;;&lt;br /&gt;
        pageName = String(mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell());&lt;br /&gt;
&lt;br /&gt;
        if (!viewer) {&lt;br /&gt;
            viewer = document.createElement(&#039;pre&#039;);&lt;br /&gt;
            viewer.id = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            viewer.className = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            output.insertBefore(viewer, source);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
        if (!viewer.textContent &amp;amp;&amp;amp; fallbackText) {&lt;br /&gt;
            viewer.textContent = fallbackText;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        source.classList.add(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
        source.setAttribute(&#039;data-clbi-system-source-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        source.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        viewer.scrollTop = currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (viewer.getAttribute(&#039;data-clbi-raw-title&#039;) === pageName &amp;amp;&amp;amp; viewer.getAttribute(&#039;data-clbi-raw-loaded&#039;) === &#039;1&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        viewer.setAttribute(&#039;data-clbi-raw-title&#039;, pageName);&lt;br /&gt;
        token = ++systemDocRawFetchToken;&lt;br /&gt;
&lt;br /&gt;
        fetch(getSystemDocRawUrlForShell(), { credentials: &#039;same-origin&#039; })&lt;br /&gt;
            .then(function (res) {&lt;br /&gt;
                if (!res.ok) throw new Error(&#039;raw fetch failed &#039; + res.status);&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function (text) {&lt;br /&gt;
                if (token !== systemDocRawFetchToken) return;&lt;br /&gt;
&lt;br /&gt;
                currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
                if (text &amp;amp;&amp;amp; viewer.textContent !== text) {&lt;br /&gt;
                    viewer.textContent = text;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;1&#039;);&lt;br /&gt;
                viewer.scrollTop = currentScrollTop;&lt;br /&gt;
            })&lt;br /&gt;
            .catch(function () {&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;0&#039;);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        systemDocRendering = true;&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!row) {&lt;br /&gt;
            row = document.createElement(&#039;div&#039;);&lt;br /&gt;
            row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
            row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
            box = document.createElement(&#039;div&#039;);&lt;br /&gt;
            box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
            meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
            label = document.createElement(&#039;span&#039;);&lt;br /&gt;
            label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
            label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
            type = document.createElement(&#039;span&#039;);&lt;br /&gt;
            type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
&lt;br /&gt;
            title = document.createElement(&#039;div&#039;);&lt;br /&gt;
            title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta.appendChild(label);&lt;br /&gt;
            meta.appendChild(type);&lt;br /&gt;
            box.appendChild(meta);&lt;br /&gt;
            box.appendChild(title);&lt;br /&gt;
            row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
            anchor = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
            main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
            if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
                anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
            } else if (main) {&lt;br /&gt;
                main.insertBefore(row, main.firstChild);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        type = row.querySelector(&#039;.clbi-system-doc-type&#039;);&lt;br /&gt;
        title = row.querySelector(&#039;.clbi-system-doc-title&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (type) type.textContent = ext;&lt;br /&gt;
        if (title) title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        renderSystemDocSourceViewerForShell();&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function () {&lt;br /&gt;
            systemDocRendering = false;&lt;br /&gt;
        }, 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            removeSystemDocIndicatorForShell();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (systemDocRendering) return;&lt;br /&gt;
&lt;br /&gt;
            if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
                if (&lt;br /&gt;
                    document.getElementById(&#039;clbi-system-doc-indicator-row&#039;) &amp;amp;&amp;amp;&lt;br /&gt;
                    document.getElementById(&#039;clbi-system-source-viewer&#039;)&lt;br /&gt;
                ) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;resize&#039;, function () {&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            window.setTimeout(applySystemDocSourceViewerLayoutForShell, 0);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        renderSystemDocSourceViewer: renderSystemDocSourceViewerForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell,&lt;br /&gt;
        refreshSystemDocSourceViewer: renderSystemDocSourceViewerForShell,&lt;br /&gt;
        layoutSystemDocSourceViewer: applySystemDocSourceViewerLayoutForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2472</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2472"/>
		<updated>2026-06-02T20:45:26Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
MediaWiki CSS/JS 문서는 기본 제목을 숨기고 우상단 시스템 문서 표식만 띄운다.&lt;br /&gt;
캐시 안내문은 유지한다.&lt;br /&gt;
원본 SyntaxHighlight 출력은 숨기고, Common.js가 만든 읽기 전용 raw viewer만 스크롤한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; :not(#clbi-system-source-viewer):not(#clbi-system-doc-indicator-row) {&lt;br /&gt;
flex:0 0 auto !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-original-source-hidden {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page #clbi-system-source-viewer {&lt;br /&gt;
display:block !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 0 !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
margin:8px 0 0 !important;&lt;br /&gt;
padding:8px 10px !important;&lt;br /&gt;
overflow:auto !important;&lt;br /&gt;
background:#f3f6f7 !important;&lt;br /&gt;
color:#111111 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
outline:none !important;&lt;br /&gt;
font-family:Consolas, Monaco, &#039;Courier New&#039;, monospace !important;&lt;br /&gt;
font-size:12px !important;&lt;br /&gt;
line-height:1.45 !important;&lt;br /&gt;
white-space:pre !important;&lt;br /&gt;
tab-size:4;&lt;br /&gt;
scrollbar-gutter:stable;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:8px !important;&lt;br /&gt;
right:8px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 16px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
max-width:520px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:7px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:0.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
max-width:500px !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:24px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:0.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78) !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
word-break:normal !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2471</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2471"/>
		<updated>2026-06-02T20:36:59Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    var systemDocRawFetchToken = 0;&lt;br /&gt;
&lt;br /&gt;
    function cleanupLegacySystemDocCodeMutationsForShell() {&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codepane&#039;).forEach(function (pane) {&lt;br /&gt;
            var parent;&lt;br /&gt;
            if (!pane || !pane.parentNode) return;&lt;br /&gt;
&lt;br /&gt;
            parent = pane.parentNode;&lt;br /&gt;
            while (pane.firstChild) {&lt;br /&gt;
                parent.insertBefore(pane.firstChild, pane);&lt;br /&gt;
            }&lt;br /&gt;
            parent.removeChild(pane);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codebox&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;box-sizing&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;flex&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;max-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;background&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;color&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function findSystemDocSourceNodeForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var children;&lt;br /&gt;
        var preferred;&lt;br /&gt;
&lt;br /&gt;
        if (!output) return null;&lt;br /&gt;
&lt;br /&gt;
        children = Array.prototype.slice.call(output.children || [])&lt;br /&gt;
            .filter(function (el) {&lt;br /&gt;
                return el &amp;amp;&amp;amp; el.nodeType === 1 &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-doc-indicator-row&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-source-viewer&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    !el.classList.contains(&#039;catlinks&#039;) &amp;amp;&amp;amp;&lt;br /&gt;
                    (el.textContent || &#039;&#039;).trim().length &amp;gt; 200;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        preferred = children.filter(function (el) {&lt;br /&gt;
            return el.matches &amp;amp;&amp;amp; el.matches(&#039;.mw-highlight, .mw-code, pre&#039;);&lt;br /&gt;
        })[0];&lt;br /&gt;
&lt;br /&gt;
        return preferred || children.sort(function (a, b) {&lt;br /&gt;
            return (b.textContent || &#039;&#039;).trim().length - (a.textContent || &#039;&#039;).trim().length;&lt;br /&gt;
        })[0] || null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getSystemDocRawUrlForShell() {&lt;br /&gt;
        var title = mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.util &amp;amp;&amp;amp; typeof mw.util.getUrl === &#039;function&#039;) {&lt;br /&gt;
            return mw.util.getUrl(title, {&lt;br /&gt;
                action: &#039;raw&#039;,&lt;br /&gt;
                ctype: &#039;text/plain&#039;,&lt;br /&gt;
                _: String(Date.now())&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &#039;/index.php?title=&#039; + encodeURIComponent(title) + &#039;&amp;amp;action=raw&amp;amp;ctype=text/plain&amp;amp;_=&#039; + Date.now();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocSourceViewerForShell() {&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (viewer &amp;amp;&amp;amp; viewer.parentNode) {&lt;br /&gt;
            viewer.parentNode.removeChild(viewer);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-original-source-hidden&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-source-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySystemDocSourceViewerLayoutForShell() {&lt;br /&gt;
        /*&lt;br /&gt;
        CSS owns the source viewer layout.&lt;br /&gt;
&lt;br /&gt;
        Earlier versions recalculated pixel heights on every refresh. That made&lt;br /&gt;
        the viewer fight the fixed page shell and caused the blue inspector&lt;br /&gt;
        flashing / disappearing bottom gap.  The viewer is now a normal flex&lt;br /&gt;
        child of .mw-parser-output; JS only creates it and supplies text.&lt;br /&gt;
        */&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!viewer || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        viewer.removeAttribute(&#039;style&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocSourceViewerForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var source;&lt;br /&gt;
        var viewer;&lt;br /&gt;
        var fallbackText;&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var token;&lt;br /&gt;
        var currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (!output || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
&lt;br /&gt;
        source = findSystemDocSourceNodeForShell();&lt;br /&gt;
        if (!source) return;&lt;br /&gt;
&lt;br /&gt;
        viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
        fallbackText = source.textContent || &#039;&#039;;&lt;br /&gt;
        pageName = String(mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell());&lt;br /&gt;
&lt;br /&gt;
        if (!viewer) {&lt;br /&gt;
            viewer = document.createElement(&#039;pre&#039;);&lt;br /&gt;
            viewer.id = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            viewer.className = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            output.insertBefore(viewer, source);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
        if (!viewer.textContent &amp;amp;&amp;amp; fallbackText) {&lt;br /&gt;
            viewer.textContent = fallbackText;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        source.classList.add(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
        source.setAttribute(&#039;data-clbi-system-source-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        source.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        applySystemDocSourceViewerLayoutForShell();&lt;br /&gt;
        viewer.scrollTop = currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (viewer.getAttribute(&#039;data-clbi-raw-title&#039;) === pageName &amp;amp;&amp;amp; viewer.getAttribute(&#039;data-clbi-raw-loaded&#039;) === &#039;1&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        viewer.setAttribute(&#039;data-clbi-raw-title&#039;, pageName);&lt;br /&gt;
        token = ++systemDocRawFetchToken;&lt;br /&gt;
&lt;br /&gt;
        fetch(getSystemDocRawUrlForShell(), { credentials: &#039;same-origin&#039; })&lt;br /&gt;
            .then(function (res) {&lt;br /&gt;
                if (!res.ok) throw new Error(&#039;raw fetch failed &#039; + res.status);&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function (text) {&lt;br /&gt;
                if (token !== systemDocRawFetchToken) return;&lt;br /&gt;
&lt;br /&gt;
                currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
                if (text &amp;amp;&amp;amp; viewer.textContent !== text) {&lt;br /&gt;
                    viewer.textContent = text;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;1&#039;);&lt;br /&gt;
                applySystemDocSourceViewerLayoutForShell();&lt;br /&gt;
                viewer.scrollTop = currentScrollTop;&lt;br /&gt;
            })&lt;br /&gt;
            .catch(function () {&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;0&#039;);&lt;br /&gt;
                applySystemDocSourceViewerLayoutForShell();&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
        var existing;&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) { existing.parentNode.removeChild(existing); }&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.createElement(&#039;div&#039;);&lt;br /&gt;
        row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
        row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
        box = document.createElement(&#039;div&#039;);&lt;br /&gt;
        box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
        meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
        meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
        label = document.createElement(&#039;span&#039;);&lt;br /&gt;
        label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
        label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
        type = document.createElement(&#039;span&#039;);&lt;br /&gt;
        type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
        type.textContent = ext;&lt;br /&gt;
&lt;br /&gt;
        title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
        title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        meta.appendChild(label);&lt;br /&gt;
        meta.appendChild(type);&lt;br /&gt;
        box.appendChild(meta);&lt;br /&gt;
        box.appendChild(title);&lt;br /&gt;
        row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
        anchor = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
            anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
        } else if (main) {&lt;br /&gt;
            main.insertBefore(row, main.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        renderSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            removeSystemDocIndicatorForShell();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;resize&#039;, function () {&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            window.setTimeout(applySystemDocSourceViewerLayoutForShell, 0);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        renderSystemDocSourceViewer: renderSystemDocSourceViewerForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell,&lt;br /&gt;
        refreshSystemDocSourceViewer: renderSystemDocSourceViewerForShell,&lt;br /&gt;
        layoutSystemDocSourceViewer: applySystemDocSourceViewerLayoutForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2470</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2470"/>
		<updated>2026-06-02T20:36:51Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
MediaWiki CSS/JS 문서는 기본 제목을 숨기고 우상단 시스템 문서 표식만 띄운다.&lt;br /&gt;
캐시 안내문은 유지한다.&lt;br /&gt;
원본 SyntaxHighlight 출력은 숨기고, Common.js가 만든 읽기 전용 raw viewer가&lt;br /&gt;
.mw-parser-output 내부 우물의 남은 높이를 차지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; :not(#clbi-system-source-viewer):not(#clbi-system-doc-indicator-row) {&lt;br /&gt;
flex:0 0 auto !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-original-source-hidden {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page #clbi-system-source-viewer {&lt;br /&gt;
display:block !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 0 !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
margin:8px 0 0 !important;&lt;br /&gt;
padding:8px 10px !important;&lt;br /&gt;
overflow:auto !important;&lt;br /&gt;
background:#f3f6f7 !important;&lt;br /&gt;
color:#111111 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
outline:none !important;&lt;br /&gt;
font-family:Consolas, Monaco, &#039;Courier New&#039;, monospace !important;&lt;br /&gt;
font-size:12px !important;&lt;br /&gt;
line-height:1.45 !important;&lt;br /&gt;
white-space:pre !important;&lt;br /&gt;
tab-size:4;&lt;br /&gt;
scrollbar-gutter:stable;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:8px !important;&lt;br /&gt;
right:8px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 16px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
max-width:520px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:7px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:0.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
max-width:500px !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:24px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:0.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78) !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
word-break:normal !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2469</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2469"/>
		<updated>2026-06-02T20:33:00Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    var systemDocRawFetchToken = 0;&lt;br /&gt;
    var systemDocLayoutRaf = 0;&lt;br /&gt;
&lt;br /&gt;
    function cleanupLegacySystemDocCodeMutationsForShell() {&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codepane&#039;).forEach(function (pane) {&lt;br /&gt;
            var parent;&lt;br /&gt;
            if (!pane || !pane.parentNode) return;&lt;br /&gt;
&lt;br /&gt;
            parent = pane.parentNode;&lt;br /&gt;
            while (pane.firstChild) {&lt;br /&gt;
                parent.insertBefore(pane.firstChild, pane);&lt;br /&gt;
            }&lt;br /&gt;
            parent.removeChild(pane);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codebox&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;box-sizing&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;flex&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;max-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;background&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;color&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function findSystemDocSourceNodeForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var children;&lt;br /&gt;
        var preferred;&lt;br /&gt;
&lt;br /&gt;
        if (!output) return null;&lt;br /&gt;
&lt;br /&gt;
        children = Array.prototype.slice.call(output.children || [])&lt;br /&gt;
            .filter(function (el) {&lt;br /&gt;
                return el &amp;amp;&amp;amp; el.nodeType === 1 &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-doc-indicator-row&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-source-viewer&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    !el.classList.contains(&#039;catlinks&#039;) &amp;amp;&amp;amp;&lt;br /&gt;
                    (el.textContent || &#039;&#039;).trim().length &amp;gt; 200;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        preferred = children.filter(function (el) {&lt;br /&gt;
            return el.matches &amp;amp;&amp;amp; el.matches(&#039;.mw-highlight, .mw-code, pre&#039;);&lt;br /&gt;
        })[0];&lt;br /&gt;
&lt;br /&gt;
        return preferred || children.sort(function (a, b) {&lt;br /&gt;
            return (b.textContent || &#039;&#039;).trim().length - (a.textContent || &#039;&#039;).trim().length;&lt;br /&gt;
        })[0] || null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getSystemDocRawUrlForShell() {&lt;br /&gt;
        var title = mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.util &amp;amp;&amp;amp; typeof mw.util.getUrl === &#039;function&#039;) {&lt;br /&gt;
            return mw.util.getUrl(title, {&lt;br /&gt;
                action: &#039;raw&#039;,&lt;br /&gt;
                ctype: &#039;text/plain&#039;,&lt;br /&gt;
                _: String(Date.now())&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &#039;/index.php?title=&#039; + encodeURIComponent(title) + &#039;&amp;amp;action=raw&amp;amp;ctype=text/plain&amp;amp;_=&#039; + Date.now();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocSourceViewerForShell() {&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (systemDocLayoutRaf) {&lt;br /&gt;
            cancelAnimationFrame(systemDocLayoutRaf);&lt;br /&gt;
            systemDocLayoutRaf = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (viewer &amp;amp;&amp;amp; viewer.parentNode) {&lt;br /&gt;
            viewer.parentNode.removeChild(viewer);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-original-source-hidden&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-source-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySystemDocSourceViewerLayoutForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
        var indicator = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
        var outputRect;&lt;br /&gt;
        var outputStyle;&lt;br /&gt;
        var outputPaddingBottom;&lt;br /&gt;
        var viewerTop;&lt;br /&gt;
        var viewerBottom;&lt;br /&gt;
        var viewerHeight;&lt;br /&gt;
        var currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (!output || !main || !viewer || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
        output.style.setProperty(&#039;display&#039;, &#039;flex&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;flex-direction&#039;, &#039;column&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;height&#039;, &#039;auto&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;position&#039;, &#039;relative&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        Array.prototype.slice.call(output.children || []).forEach(function (el) {&lt;br /&gt;
            if (!el || el === viewer || el === indicator) return;&lt;br /&gt;
            el.style.setProperty(&#039;flex&#039;, &#039;0 0 auto&#039;, &#039;important&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        main.style.setProperty(&#039;display&#039;, &#039;flex&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;flex-direction&#039;, &#039;column&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        viewer.style.setProperty(&#039;display&#039;, &#039;block&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;box-sizing&#039;, &#039;border-box&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;flex&#039;, &#039;0 0 auto&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;width&#039;, &#039;100%&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;max-width&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;margin&#039;, &#039;8px 0 0&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;padding&#039;, &#039;8px 10px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;overflow&#039;, &#039;auto&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;background&#039;, &#039;#f3f6f7&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;color&#039;, &#039;#111111&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;border&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;outline&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;font-family&#039;, &amp;quot;Consolas, Monaco, &#039;Courier New&#039;, monospace&amp;quot;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;font-size&#039;, &#039;12px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;line-height&#039;, &#039;1.45&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;white-space&#039;, &#039;pre&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;tab-size&#039;, &#039;4&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;scrollbar-gutter&#039;, &#039;stable&#039;);&lt;br /&gt;
&lt;br /&gt;
        outputRect = output.getBoundingClientRect();&lt;br /&gt;
        outputStyle = window.getComputedStyle(output);&lt;br /&gt;
        outputPaddingBottom = parseFloat(outputStyle.paddingBottom || &#039;0&#039;) || 0;&lt;br /&gt;
        viewerTop = viewer.getBoundingClientRect().top;&lt;br /&gt;
        viewerBottom = outputRect.bottom - outputPaddingBottom;&lt;br /&gt;
&lt;br /&gt;
        viewerHeight = Math.max(260, Math.round(viewerBottom - viewerTop));&lt;br /&gt;
&lt;br /&gt;
        viewer.style.setProperty(&#039;height&#039;, viewerHeight + &#039;px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;max-height&#039;, viewerHeight + &#039;px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.scrollTop = currentScrollTop;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function scheduleSystemDocSourceViewerLayoutForShell() {&lt;br /&gt;
        if (systemDocLayoutRaf) {&lt;br /&gt;
            cancelAnimationFrame(systemDocLayoutRaf);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        systemDocLayoutRaf = requestAnimationFrame(function () {&lt;br /&gt;
            systemDocLayoutRaf = 0;&lt;br /&gt;
            applySystemDocSourceViewerLayoutForShell();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocSourceViewerForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var source;&lt;br /&gt;
        var viewer;&lt;br /&gt;
        var fallbackText;&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var token;&lt;br /&gt;
        var currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (!output || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
&lt;br /&gt;
        source = findSystemDocSourceNodeForShell();&lt;br /&gt;
        if (!source) return;&lt;br /&gt;
&lt;br /&gt;
        viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
        fallbackText = source.textContent || &#039;&#039;;&lt;br /&gt;
        pageName = String(mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell());&lt;br /&gt;
&lt;br /&gt;
        if (!viewer) {&lt;br /&gt;
            viewer = document.createElement(&#039;pre&#039;);&lt;br /&gt;
            viewer.id = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            viewer.className = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            output.insertBefore(viewer, source);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
        if (!viewer.textContent &amp;amp;&amp;amp; fallbackText) {&lt;br /&gt;
            viewer.textContent = fallbackText;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        source.classList.add(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
        source.setAttribute(&#039;data-clbi-system-source-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        source.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        scheduleSystemDocSourceViewerLayoutForShell();&lt;br /&gt;
        viewer.scrollTop = currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (viewer.getAttribute(&#039;data-clbi-raw-title&#039;) === pageName &amp;amp;&amp;amp; viewer.getAttribute(&#039;data-clbi-raw-loaded&#039;) === &#039;1&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        viewer.setAttribute(&#039;data-clbi-raw-title&#039;, pageName);&lt;br /&gt;
        token = ++systemDocRawFetchToken;&lt;br /&gt;
&lt;br /&gt;
        fetch(getSystemDocRawUrlForShell(), { credentials: &#039;same-origin&#039; })&lt;br /&gt;
            .then(function (res) {&lt;br /&gt;
                if (!res.ok) throw new Error(&#039;raw fetch failed &#039; + res.status);&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function (text) {&lt;br /&gt;
                if (token !== systemDocRawFetchToken) return;&lt;br /&gt;
&lt;br /&gt;
                currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
                if (text &amp;amp;&amp;amp; viewer.textContent !== text) {&lt;br /&gt;
                    viewer.textContent = text;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;1&#039;);&lt;br /&gt;
                scheduleSystemDocSourceViewerLayoutForShell();&lt;br /&gt;
                viewer.scrollTop = currentScrollTop;&lt;br /&gt;
            })&lt;br /&gt;
            .catch(function () {&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;0&#039;);&lt;br /&gt;
                scheduleSystemDocSourceViewerLayoutForShell();&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!row) {&lt;br /&gt;
            row = document.createElement(&#039;div&#039;);&lt;br /&gt;
            row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
            row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
            box = document.createElement(&#039;div&#039;);&lt;br /&gt;
            box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
            meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
            label = document.createElement(&#039;span&#039;);&lt;br /&gt;
            label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
            label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
            type = document.createElement(&#039;span&#039;);&lt;br /&gt;
            type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
&lt;br /&gt;
            title = document.createElement(&#039;div&#039;);&lt;br /&gt;
            title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta.appendChild(label);&lt;br /&gt;
            meta.appendChild(type);&lt;br /&gt;
            box.appendChild(meta);&lt;br /&gt;
            box.appendChild(title);&lt;br /&gt;
            row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
            anchor = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
            main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
            if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
                anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
            } else if (main) {&lt;br /&gt;
                main.insertBefore(row, main.firstChild);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        type = row.querySelector(&#039;.clbi-system-doc-type&#039;);&lt;br /&gt;
        title = row.querySelector(&#039;.clbi-system-doc-title&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (type) type.textContent = ext;&lt;br /&gt;
        if (title) title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        renderSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            removeSystemDocIndicatorForShell();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;resize&#039;, function () {&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            window.setTimeout(scheduleSystemDocSourceViewerLayoutForShell, 0);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        renderSystemDocSourceViewer: renderSystemDocSourceViewerForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell,&lt;br /&gt;
        refreshSystemDocSourceViewer: renderSystemDocSourceViewerForShell,&lt;br /&gt;
        layoutSystemDocSourceViewer: scheduleSystemDocSourceViewerLayoutForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2468</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2468"/>
		<updated>2026-06-02T20:13:33Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    var systemDocRawFetchToken = 0;&lt;br /&gt;
&lt;br /&gt;
    function cleanupLegacySystemDocCodeMutationsForShell() {&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codepane&#039;).forEach(function (pane) {&lt;br /&gt;
            var parent;&lt;br /&gt;
            if (!pane || !pane.parentNode) return;&lt;br /&gt;
&lt;br /&gt;
            parent = pane.parentNode;&lt;br /&gt;
            while (pane.firstChild) {&lt;br /&gt;
                parent.insertBefore(pane.firstChild, pane);&lt;br /&gt;
            }&lt;br /&gt;
            parent.removeChild(pane);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codebox&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;box-sizing&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;flex&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;max-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;background&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;color&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function findSystemDocSourceNodeForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var children;&lt;br /&gt;
        var preferred;&lt;br /&gt;
&lt;br /&gt;
        if (!output) return null;&lt;br /&gt;
&lt;br /&gt;
        children = Array.prototype.slice.call(output.children || [])&lt;br /&gt;
            .filter(function (el) {&lt;br /&gt;
                return el &amp;amp;&amp;amp; el.nodeType === 1 &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-doc-indicator-row&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-source-viewer&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    !el.classList.contains(&#039;catlinks&#039;) &amp;amp;&amp;amp;&lt;br /&gt;
                    (el.textContent || &#039;&#039;).trim().length &amp;gt; 200;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        preferred = children.filter(function (el) {&lt;br /&gt;
            return el.matches &amp;amp;&amp;amp; el.matches(&#039;.mw-highlight, .mw-code, pre&#039;);&lt;br /&gt;
        })[0];&lt;br /&gt;
&lt;br /&gt;
        return preferred || children.sort(function (a, b) {&lt;br /&gt;
            return (b.textContent || &#039;&#039;).trim().length - (a.textContent || &#039;&#039;).trim().length;&lt;br /&gt;
        })[0] || null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getSystemDocRawUrlForShell() {&lt;br /&gt;
        var title = mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.util &amp;amp;&amp;amp; typeof mw.util.getUrl === &#039;function&#039;) {&lt;br /&gt;
            return mw.util.getUrl(title, {&lt;br /&gt;
                action: &#039;raw&#039;,&lt;br /&gt;
                ctype: &#039;text/plain&#039;,&lt;br /&gt;
                _: String(Date.now())&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &#039;/index.php?title=&#039; + encodeURIComponent(title) + &#039;&amp;amp;action=raw&amp;amp;ctype=text/plain&amp;amp;_=&#039; + Date.now();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocSourceViewerForShell() {&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (viewer &amp;amp;&amp;amp; viewer.parentNode) {&lt;br /&gt;
            viewer.parentNode.removeChild(viewer);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-original-source-hidden&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-source-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySystemDocSourceViewerLayoutForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
        var indicator = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
        var bottomNav = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
        var viewerTop;&lt;br /&gt;
        var mainBottom;&lt;br /&gt;
        var viewerHeight;&lt;br /&gt;
        var currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (!output || !main || !viewer || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
        output.style.setProperty(&#039;display&#039;, &#039;flex&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;flex-direction&#039;, &#039;column&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;height&#039;, &#039;auto&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;position&#039;, &#039;relative&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        Array.prototype.slice.call(output.children || []).forEach(function (el) {&lt;br /&gt;
            if (!el || el === viewer || el === indicator) return;&lt;br /&gt;
            el.style.setProperty(&#039;flex&#039;, &#039;0 0 auto&#039;, &#039;important&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        main.style.setProperty(&#039;display&#039;, &#039;flex&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;flex-direction&#039;, &#039;column&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        viewer.style.setProperty(&#039;display&#039;, &#039;block&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;box-sizing&#039;, &#039;border-box&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;flex&#039;, &#039;0 0 auto&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;width&#039;, &#039;100%&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;max-width&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;margin&#039;, &#039;8px 0 0&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;padding&#039;, &#039;8px 10px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;overflow&#039;, &#039;auto&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;background&#039;, &#039;#f3f6f7&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;color&#039;, &#039;#111111&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;border&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;outline&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;font-family&#039;, &amp;quot;Consolas, Monaco, &#039;Courier New&#039;, monospace&amp;quot;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;font-size&#039;, &#039;12px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;line-height&#039;, &#039;1.45&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;white-space&#039;, &#039;pre&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;tab-size&#039;, &#039;4&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;scrollbar-gutter&#039;, &#039;stable&#039;);&lt;br /&gt;
&lt;br /&gt;
        viewerTop = viewer.getBoundingClientRect().top;&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        046 used .mw-parser-output&#039;s bottom as the measurement base. On system&lt;br /&gt;
        source pages that value can collapse to the current source-viewer height&lt;br /&gt;
        during the first layout pass, so the viewer was locked at the 260px&lt;br /&gt;
        fallback and a large empty 080808 well appeared below it.&lt;br /&gt;
&lt;br /&gt;
        Use the stable outer content frame bottom instead, then leave a real&lt;br /&gt;
        lower closing gutter inside the well. This keeps the source viewer tall&lt;br /&gt;
        while preserving the visible bottom finish above the bottom nav.&lt;br /&gt;
        */&lt;br /&gt;
        mainBottom = main.getBoundingClientRect().bottom - 16;&lt;br /&gt;
&lt;br /&gt;
        if (bottomNav) {&lt;br /&gt;
            mainBottom = Math.min(mainBottom, bottomNav.getBoundingClientRect().top - 24);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        viewerHeight = Math.max(260, Math.round(mainBottom - viewerTop));&lt;br /&gt;
&lt;br /&gt;
        viewer.style.setProperty(&#039;height&#039;, viewerHeight + &#039;px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;max-height&#039;, viewerHeight + &#039;px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.scrollTop = currentScrollTop;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocSourceViewerForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var source;&lt;br /&gt;
        var viewer;&lt;br /&gt;
        var fallbackText;&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var token;&lt;br /&gt;
        var currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (!output || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
&lt;br /&gt;
        source = findSystemDocSourceNodeForShell();&lt;br /&gt;
        if (!source) return;&lt;br /&gt;
&lt;br /&gt;
        viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
        fallbackText = source.textContent || &#039;&#039;;&lt;br /&gt;
        pageName = String(mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell());&lt;br /&gt;
&lt;br /&gt;
        if (!viewer) {&lt;br /&gt;
            viewer = document.createElement(&#039;pre&#039;);&lt;br /&gt;
            viewer.id = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            viewer.className = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            output.insertBefore(viewer, source);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
        if (!viewer.textContent &amp;amp;&amp;amp; fallbackText) {&lt;br /&gt;
            viewer.textContent = fallbackText;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        source.classList.add(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
        source.setAttribute(&#039;data-clbi-system-source-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        source.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        applySystemDocSourceViewerLayoutForShell();&lt;br /&gt;
        viewer.scrollTop = currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (viewer.getAttribute(&#039;data-clbi-raw-title&#039;) === pageName &amp;amp;&amp;amp; viewer.getAttribute(&#039;data-clbi-raw-loaded&#039;) === &#039;1&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        viewer.setAttribute(&#039;data-clbi-raw-title&#039;, pageName);&lt;br /&gt;
        token = ++systemDocRawFetchToken;&lt;br /&gt;
&lt;br /&gt;
        fetch(getSystemDocRawUrlForShell(), { credentials: &#039;same-origin&#039; })&lt;br /&gt;
            .then(function (res) {&lt;br /&gt;
                if (!res.ok) throw new Error(&#039;raw fetch failed &#039; + res.status);&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function (text) {&lt;br /&gt;
                if (token !== systemDocRawFetchToken) return;&lt;br /&gt;
&lt;br /&gt;
                currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
                if (text &amp;amp;&amp;amp; viewer.textContent !== text) {&lt;br /&gt;
                    viewer.textContent = text;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;1&#039;);&lt;br /&gt;
                applySystemDocSourceViewerLayoutForShell();&lt;br /&gt;
                viewer.scrollTop = currentScrollTop;&lt;br /&gt;
            })&lt;br /&gt;
            .catch(function () {&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;0&#039;);&lt;br /&gt;
                applySystemDocSourceViewerLayoutForShell();&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
        var existing;&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) { existing.parentNode.removeChild(existing); }&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.createElement(&#039;div&#039;);&lt;br /&gt;
        row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
        row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
        box = document.createElement(&#039;div&#039;);&lt;br /&gt;
        box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
        meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
        meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
        label = document.createElement(&#039;span&#039;);&lt;br /&gt;
        label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
        label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
        type = document.createElement(&#039;span&#039;);&lt;br /&gt;
        type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
        type.textContent = ext;&lt;br /&gt;
&lt;br /&gt;
        title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
        title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        meta.appendChild(label);&lt;br /&gt;
        meta.appendChild(type);&lt;br /&gt;
        box.appendChild(meta);&lt;br /&gt;
        box.appendChild(title);&lt;br /&gt;
        row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
        anchor = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
            anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
        } else if (main) {&lt;br /&gt;
            main.insertBefore(row, main.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        renderSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            removeSystemDocIndicatorForShell();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;resize&#039;, function () {&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            window.setTimeout(applySystemDocSourceViewerLayoutForShell, 0);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        renderSystemDocSourceViewer: renderSystemDocSourceViewerForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell,&lt;br /&gt;
        refreshSystemDocSourceViewer: renderSystemDocSourceViewerForShell,&lt;br /&gt;
        layoutSystemDocSourceViewer: applySystemDocSourceViewerLayoutForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2467</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2467"/>
		<updated>2026-06-02T20:09:25Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    var systemDocRawFetchToken = 0;&lt;br /&gt;
&lt;br /&gt;
    function cleanupLegacySystemDocCodeMutationsForShell() {&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codepane&#039;).forEach(function (pane) {&lt;br /&gt;
            var parent;&lt;br /&gt;
            if (!pane || !pane.parentNode) return;&lt;br /&gt;
&lt;br /&gt;
            parent = pane.parentNode;&lt;br /&gt;
            while (pane.firstChild) {&lt;br /&gt;
                parent.insertBefore(pane.firstChild, pane);&lt;br /&gt;
            }&lt;br /&gt;
            parent.removeChild(pane);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codebox&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;box-sizing&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;flex&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;max-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;background&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;color&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function findSystemDocSourceNodeForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var children;&lt;br /&gt;
        var preferred;&lt;br /&gt;
&lt;br /&gt;
        if (!output) return null;&lt;br /&gt;
&lt;br /&gt;
        children = Array.prototype.slice.call(output.children || [])&lt;br /&gt;
            .filter(function (el) {&lt;br /&gt;
                return el &amp;amp;&amp;amp; el.nodeType === 1 &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-doc-indicator-row&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-source-viewer&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    !el.classList.contains(&#039;catlinks&#039;) &amp;amp;&amp;amp;&lt;br /&gt;
                    (el.textContent || &#039;&#039;).trim().length &amp;gt; 200;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        preferred = children.filter(function (el) {&lt;br /&gt;
            return el.matches &amp;amp;&amp;amp; el.matches(&#039;.mw-highlight, .mw-code, pre&#039;);&lt;br /&gt;
        })[0];&lt;br /&gt;
&lt;br /&gt;
        return preferred || children.sort(function (a, b) {&lt;br /&gt;
            return (b.textContent || &#039;&#039;).trim().length - (a.textContent || &#039;&#039;).trim().length;&lt;br /&gt;
        })[0] || null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getSystemDocRawUrlForShell() {&lt;br /&gt;
        var title = mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.util &amp;amp;&amp;amp; typeof mw.util.getUrl === &#039;function&#039;) {&lt;br /&gt;
            return mw.util.getUrl(title, {&lt;br /&gt;
                action: &#039;raw&#039;,&lt;br /&gt;
                ctype: &#039;text/plain&#039;,&lt;br /&gt;
                _: String(Date.now())&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &#039;/index.php?title=&#039; + encodeURIComponent(title) + &#039;&amp;amp;action=raw&amp;amp;ctype=text/plain&amp;amp;_=&#039; + Date.now();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocSourceViewerForShell() {&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (viewer &amp;amp;&amp;amp; viewer.parentNode) {&lt;br /&gt;
            viewer.parentNode.removeChild(viewer);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-original-source-hidden&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-source-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySystemDocSourceViewerLayoutForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
        var indicator = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
        var bottomNav = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
        var viewerTop;&lt;br /&gt;
        var mainBottom;&lt;br /&gt;
        var viewerHeight;&lt;br /&gt;
        var currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (!output || !main || !viewer || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
        output.style.setProperty(&#039;display&#039;, &#039;flex&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;flex-direction&#039;, &#039;column&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;height&#039;, &#039;auto&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;position&#039;, &#039;relative&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        Array.prototype.slice.call(output.children || []).forEach(function (el) {&lt;br /&gt;
            if (!el || el === viewer || el === indicator) return;&lt;br /&gt;
            el.style.setProperty(&#039;flex&#039;, &#039;0 0 auto&#039;, &#039;important&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        main.style.setProperty(&#039;display&#039;, &#039;flex&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;flex-direction&#039;, &#039;column&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        viewer.style.setProperty(&#039;display&#039;, &#039;block&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;box-sizing&#039;, &#039;border-box&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;flex&#039;, &#039;0 0 auto&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;width&#039;, &#039;100%&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;max-width&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;margin&#039;, &#039;8px 0 0&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;padding&#039;, &#039;8px 10px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;overflow&#039;, &#039;auto&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;background&#039;, &#039;#f3f6f7&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;color&#039;, &#039;#111111&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;border&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;outline&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;font-family&#039;, &amp;quot;Consolas, Monaco, &#039;Courier New&#039;, monospace&amp;quot;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;font-size&#039;, &#039;12px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;line-height&#039;, &#039;1.45&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;white-space&#039;, &#039;pre&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;tab-size&#039;, &#039;4&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;scrollbar-gutter&#039;, &#039;stable&#039;);&lt;br /&gt;
&lt;br /&gt;
        viewerTop = viewer.getBoundingClientRect().top;&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        The source viewer lives inside .mw-parser-output, not directly inside&lt;br /&gt;
        .liberty-content-main. 044 sized the viewer against the outer frame&lt;br /&gt;
        bottom, so the white source panel covered the inner-well bottom padding&lt;br /&gt;
        and visually erased the #1d1d1d closing frame above the bottom nav.&lt;br /&gt;
&lt;br /&gt;
        Use the inner well&#039;s content bottom instead:&lt;br /&gt;
        .liberty-content-main supplies the outer 1d1d1d frame,&lt;br /&gt;
        .mw-parser-output supplies the 080808 well and its 8px inner padding,&lt;br /&gt;
        and #clbi-system-source-viewer ends before that bottom padding.&lt;br /&gt;
        */&lt;br /&gt;
        var outputRect = output.getBoundingClientRect();&lt;br /&gt;
        var outputStyle = window.getComputedStyle(output);&lt;br /&gt;
        var outputPaddingBottom = parseFloat(outputStyle.paddingBottom || &#039;0&#039;) || 0;&lt;br /&gt;
        var viewerBottomGutter = outputPaddingBottom + 8;&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        The white source viewer must sit inside the 080808 well, with the same&lt;br /&gt;
        visible lower closing thickness as the left/right well spacing. 045 left&lt;br /&gt;
        only output padding below the viewer, making the bottom closure look&lt;br /&gt;
        thinner than the sides. Keep an extra 8px so the bottom reads as a real&lt;br /&gt;
        well/frame closing instead of a thin line above the bottom nav.&lt;br /&gt;
        */&lt;br /&gt;
        mainBottom = outputRect.bottom - viewerBottomGutter;&lt;br /&gt;
&lt;br /&gt;
        if (bottomNav) {&lt;br /&gt;
            mainBottom = Math.min(mainBottom, bottomNav.getBoundingClientRect().top - 24);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        viewerHeight = Math.max(260, Math.round(mainBottom - viewerTop));&lt;br /&gt;
&lt;br /&gt;
        viewer.style.setProperty(&#039;height&#039;, viewerHeight + &#039;px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;max-height&#039;, viewerHeight + &#039;px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.scrollTop = currentScrollTop;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocSourceViewerForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var source;&lt;br /&gt;
        var viewer;&lt;br /&gt;
        var fallbackText;&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var token;&lt;br /&gt;
        var currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (!output || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
&lt;br /&gt;
        source = findSystemDocSourceNodeForShell();&lt;br /&gt;
        if (!source) return;&lt;br /&gt;
&lt;br /&gt;
        viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
        fallbackText = source.textContent || &#039;&#039;;&lt;br /&gt;
        pageName = String(mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell());&lt;br /&gt;
&lt;br /&gt;
        if (!viewer) {&lt;br /&gt;
            viewer = document.createElement(&#039;pre&#039;);&lt;br /&gt;
            viewer.id = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            viewer.className = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            output.insertBefore(viewer, source);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
        if (!viewer.textContent &amp;amp;&amp;amp; fallbackText) {&lt;br /&gt;
            viewer.textContent = fallbackText;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        source.classList.add(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
        source.setAttribute(&#039;data-clbi-system-source-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        source.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        applySystemDocSourceViewerLayoutForShell();&lt;br /&gt;
        viewer.scrollTop = currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (viewer.getAttribute(&#039;data-clbi-raw-title&#039;) === pageName &amp;amp;&amp;amp; viewer.getAttribute(&#039;data-clbi-raw-loaded&#039;) === &#039;1&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        viewer.setAttribute(&#039;data-clbi-raw-title&#039;, pageName);&lt;br /&gt;
        token = ++systemDocRawFetchToken;&lt;br /&gt;
&lt;br /&gt;
        fetch(getSystemDocRawUrlForShell(), { credentials: &#039;same-origin&#039; })&lt;br /&gt;
            .then(function (res) {&lt;br /&gt;
                if (!res.ok) throw new Error(&#039;raw fetch failed &#039; + res.status);&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function (text) {&lt;br /&gt;
                if (token !== systemDocRawFetchToken) return;&lt;br /&gt;
&lt;br /&gt;
                currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
                if (text &amp;amp;&amp;amp; viewer.textContent !== text) {&lt;br /&gt;
                    viewer.textContent = text;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;1&#039;);&lt;br /&gt;
                applySystemDocSourceViewerLayoutForShell();&lt;br /&gt;
                viewer.scrollTop = currentScrollTop;&lt;br /&gt;
            })&lt;br /&gt;
            .catch(function () {&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;0&#039;);&lt;br /&gt;
                applySystemDocSourceViewerLayoutForShell();&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
        var existing;&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) { existing.parentNode.removeChild(existing); }&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.createElement(&#039;div&#039;);&lt;br /&gt;
        row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
        row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
        box = document.createElement(&#039;div&#039;);&lt;br /&gt;
        box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
        meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
        meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
        label = document.createElement(&#039;span&#039;);&lt;br /&gt;
        label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
        label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
        type = document.createElement(&#039;span&#039;);&lt;br /&gt;
        type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
        type.textContent = ext;&lt;br /&gt;
&lt;br /&gt;
        title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
        title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        meta.appendChild(label);&lt;br /&gt;
        meta.appendChild(type);&lt;br /&gt;
        box.appendChild(meta);&lt;br /&gt;
        box.appendChild(title);&lt;br /&gt;
        row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
        anchor = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
            anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
        } else if (main) {&lt;br /&gt;
            main.insertBefore(row, main.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        renderSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            removeSystemDocIndicatorForShell();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;resize&#039;, function () {&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            window.setTimeout(applySystemDocSourceViewerLayoutForShell, 0);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        renderSystemDocSourceViewer: renderSystemDocSourceViewerForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell,&lt;br /&gt;
        refreshSystemDocSourceViewer: renderSystemDocSourceViewerForShell,&lt;br /&gt;
        layoutSystemDocSourceViewer: applySystemDocSourceViewerLayoutForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2466</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2466"/>
		<updated>2026-06-02T20:05:55Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    var systemDocRawFetchToken = 0;&lt;br /&gt;
&lt;br /&gt;
    function cleanupLegacySystemDocCodeMutationsForShell() {&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codepane&#039;).forEach(function (pane) {&lt;br /&gt;
            var parent;&lt;br /&gt;
            if (!pane || !pane.parentNode) return;&lt;br /&gt;
&lt;br /&gt;
            parent = pane.parentNode;&lt;br /&gt;
            while (pane.firstChild) {&lt;br /&gt;
                parent.insertBefore(pane.firstChild, pane);&lt;br /&gt;
            }&lt;br /&gt;
            parent.removeChild(pane);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codebox&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;box-sizing&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;flex&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;max-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;background&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;color&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function findSystemDocSourceNodeForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var children;&lt;br /&gt;
        var preferred;&lt;br /&gt;
&lt;br /&gt;
        if (!output) return null;&lt;br /&gt;
&lt;br /&gt;
        children = Array.prototype.slice.call(output.children || [])&lt;br /&gt;
            .filter(function (el) {&lt;br /&gt;
                return el &amp;amp;&amp;amp; el.nodeType === 1 &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-doc-indicator-row&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-source-viewer&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    !el.classList.contains(&#039;catlinks&#039;) &amp;amp;&amp;amp;&lt;br /&gt;
                    (el.textContent || &#039;&#039;).trim().length &amp;gt; 200;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        preferred = children.filter(function (el) {&lt;br /&gt;
            return el.matches &amp;amp;&amp;amp; el.matches(&#039;.mw-highlight, .mw-code, pre&#039;);&lt;br /&gt;
        })[0];&lt;br /&gt;
&lt;br /&gt;
        return preferred || children.sort(function (a, b) {&lt;br /&gt;
            return (b.textContent || &#039;&#039;).trim().length - (a.textContent || &#039;&#039;).trim().length;&lt;br /&gt;
        })[0] || null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getSystemDocRawUrlForShell() {&lt;br /&gt;
        var title = mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.util &amp;amp;&amp;amp; typeof mw.util.getUrl === &#039;function&#039;) {&lt;br /&gt;
            return mw.util.getUrl(title, {&lt;br /&gt;
                action: &#039;raw&#039;,&lt;br /&gt;
                ctype: &#039;text/plain&#039;,&lt;br /&gt;
                _: String(Date.now())&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &#039;/index.php?title=&#039; + encodeURIComponent(title) + &#039;&amp;amp;action=raw&amp;amp;ctype=text/plain&amp;amp;_=&#039; + Date.now();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocSourceViewerForShell() {&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (viewer &amp;amp;&amp;amp; viewer.parentNode) {&lt;br /&gt;
            viewer.parentNode.removeChild(viewer);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-original-source-hidden&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-source-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySystemDocSourceViewerLayoutForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
        var indicator = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
        var bottomNav = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
        var viewerTop;&lt;br /&gt;
        var mainBottom;&lt;br /&gt;
        var viewerHeight;&lt;br /&gt;
        var currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (!output || !main || !viewer || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
        output.style.setProperty(&#039;display&#039;, &#039;flex&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;flex-direction&#039;, &#039;column&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;height&#039;, &#039;auto&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;position&#039;, &#039;relative&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        Array.prototype.slice.call(output.children || []).forEach(function (el) {&lt;br /&gt;
            if (!el || el === viewer || el === indicator) return;&lt;br /&gt;
            el.style.setProperty(&#039;flex&#039;, &#039;0 0 auto&#039;, &#039;important&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        main.style.setProperty(&#039;display&#039;, &#039;flex&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;flex-direction&#039;, &#039;column&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        viewer.style.setProperty(&#039;display&#039;, &#039;block&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;box-sizing&#039;, &#039;border-box&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;flex&#039;, &#039;0 0 auto&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;width&#039;, &#039;100%&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;max-width&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;margin&#039;, &#039;8px 0 0&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;padding&#039;, &#039;8px 10px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;overflow&#039;, &#039;auto&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;background&#039;, &#039;#f3f6f7&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;color&#039;, &#039;#111111&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;border&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;outline&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;font-family&#039;, &amp;quot;Consolas, Monaco, &#039;Courier New&#039;, monospace&amp;quot;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;font-size&#039;, &#039;12px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;line-height&#039;, &#039;1.45&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;white-space&#039;, &#039;pre&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;tab-size&#039;, &#039;4&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;scrollbar-gutter&#039;, &#039;stable&#039;);&lt;br /&gt;
&lt;br /&gt;
        viewerTop = viewer.getBoundingClientRect().top;&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        The source viewer lives inside .mw-parser-output, not directly inside&lt;br /&gt;
        .liberty-content-main. 044 sized the viewer against the outer frame&lt;br /&gt;
        bottom, so the white source panel covered the inner-well bottom padding&lt;br /&gt;
        and visually erased the #1d1d1d closing frame above the bottom nav.&lt;br /&gt;
&lt;br /&gt;
        Use the inner well&#039;s content bottom instead:&lt;br /&gt;
        .liberty-content-main supplies the outer 1d1d1d frame,&lt;br /&gt;
        .mw-parser-output supplies the 080808 well and its 8px inner padding,&lt;br /&gt;
        and #clbi-system-source-viewer ends before that bottom padding.&lt;br /&gt;
        */&lt;br /&gt;
        var outputRect = output.getBoundingClientRect();&lt;br /&gt;
        var outputStyle = window.getComputedStyle(output);&lt;br /&gt;
        var outputPaddingBottom = parseFloat(outputStyle.paddingBottom || &#039;0&#039;) || 0;&lt;br /&gt;
&lt;br /&gt;
        mainBottom = outputRect.bottom - outputPaddingBottom;&lt;br /&gt;
&lt;br /&gt;
        if (bottomNav) {&lt;br /&gt;
            mainBottom = Math.min(mainBottom, bottomNav.getBoundingClientRect().top - 16);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        viewerHeight = Math.max(260, Math.round(mainBottom - viewerTop));&lt;br /&gt;
&lt;br /&gt;
        viewer.style.setProperty(&#039;height&#039;, viewerHeight + &#039;px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;max-height&#039;, viewerHeight + &#039;px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.scrollTop = currentScrollTop;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocSourceViewerForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var source;&lt;br /&gt;
        var viewer;&lt;br /&gt;
        var fallbackText;&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var token;&lt;br /&gt;
        var currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (!output || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
&lt;br /&gt;
        source = findSystemDocSourceNodeForShell();&lt;br /&gt;
        if (!source) return;&lt;br /&gt;
&lt;br /&gt;
        viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
        fallbackText = source.textContent || &#039;&#039;;&lt;br /&gt;
        pageName = String(mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell());&lt;br /&gt;
&lt;br /&gt;
        if (!viewer) {&lt;br /&gt;
            viewer = document.createElement(&#039;pre&#039;);&lt;br /&gt;
            viewer.id = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            viewer.className = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            output.insertBefore(viewer, source);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
        if (!viewer.textContent &amp;amp;&amp;amp; fallbackText) {&lt;br /&gt;
            viewer.textContent = fallbackText;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        source.classList.add(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
        source.setAttribute(&#039;data-clbi-system-source-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        source.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        applySystemDocSourceViewerLayoutForShell();&lt;br /&gt;
        viewer.scrollTop = currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (viewer.getAttribute(&#039;data-clbi-raw-title&#039;) === pageName &amp;amp;&amp;amp; viewer.getAttribute(&#039;data-clbi-raw-loaded&#039;) === &#039;1&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        viewer.setAttribute(&#039;data-clbi-raw-title&#039;, pageName);&lt;br /&gt;
        token = ++systemDocRawFetchToken;&lt;br /&gt;
&lt;br /&gt;
        fetch(getSystemDocRawUrlForShell(), { credentials: &#039;same-origin&#039; })&lt;br /&gt;
            .then(function (res) {&lt;br /&gt;
                if (!res.ok) throw new Error(&#039;raw fetch failed &#039; + res.status);&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function (text) {&lt;br /&gt;
                if (token !== systemDocRawFetchToken) return;&lt;br /&gt;
&lt;br /&gt;
                currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
                if (text &amp;amp;&amp;amp; viewer.textContent !== text) {&lt;br /&gt;
                    viewer.textContent = text;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;1&#039;);&lt;br /&gt;
                applySystemDocSourceViewerLayoutForShell();&lt;br /&gt;
                viewer.scrollTop = currentScrollTop;&lt;br /&gt;
            })&lt;br /&gt;
            .catch(function () {&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;0&#039;);&lt;br /&gt;
                applySystemDocSourceViewerLayoutForShell();&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
        var existing;&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) { existing.parentNode.removeChild(existing); }&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.createElement(&#039;div&#039;);&lt;br /&gt;
        row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
        row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
        box = document.createElement(&#039;div&#039;);&lt;br /&gt;
        box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
        meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
        meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
        label = document.createElement(&#039;span&#039;);&lt;br /&gt;
        label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
        label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
        type = document.createElement(&#039;span&#039;);&lt;br /&gt;
        type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
        type.textContent = ext;&lt;br /&gt;
&lt;br /&gt;
        title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
        title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        meta.appendChild(label);&lt;br /&gt;
        meta.appendChild(type);&lt;br /&gt;
        box.appendChild(meta);&lt;br /&gt;
        box.appendChild(title);&lt;br /&gt;
        row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
        anchor = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
            anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
        } else if (main) {&lt;br /&gt;
            main.insertBefore(row, main.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        renderSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            removeSystemDocIndicatorForShell();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;resize&#039;, function () {&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            window.setTimeout(applySystemDocSourceViewerLayoutForShell, 0);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        renderSystemDocSourceViewer: renderSystemDocSourceViewerForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell,&lt;br /&gt;
        refreshSystemDocSourceViewer: renderSystemDocSourceViewerForShell,&lt;br /&gt;
        layoutSystemDocSourceViewer: applySystemDocSourceViewerLayoutForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2465</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2465"/>
		<updated>2026-06-02T20:01:27Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    var systemDocRawFetchToken = 0;&lt;br /&gt;
&lt;br /&gt;
    function cleanupLegacySystemDocCodeMutationsForShell() {&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codepane&#039;).forEach(function (pane) {&lt;br /&gt;
            var parent;&lt;br /&gt;
            if (!pane || !pane.parentNode) return;&lt;br /&gt;
&lt;br /&gt;
            parent = pane.parentNode;&lt;br /&gt;
            while (pane.firstChild) {&lt;br /&gt;
                parent.insertBefore(pane.firstChild, pane);&lt;br /&gt;
            }&lt;br /&gt;
            parent.removeChild(pane);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codebox&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;box-sizing&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;flex&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;max-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;background&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;color&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function findSystemDocSourceNodeForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var children;&lt;br /&gt;
        var preferred;&lt;br /&gt;
&lt;br /&gt;
        if (!output) return null;&lt;br /&gt;
&lt;br /&gt;
        children = Array.prototype.slice.call(output.children || [])&lt;br /&gt;
            .filter(function (el) {&lt;br /&gt;
                return el &amp;amp;&amp;amp; el.nodeType === 1 &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-doc-indicator-row&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-source-viewer&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    !el.classList.contains(&#039;catlinks&#039;) &amp;amp;&amp;amp;&lt;br /&gt;
                    (el.textContent || &#039;&#039;).trim().length &amp;gt; 200;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        preferred = children.filter(function (el) {&lt;br /&gt;
            return el.matches &amp;amp;&amp;amp; el.matches(&#039;.mw-highlight, .mw-code, pre&#039;);&lt;br /&gt;
        })[0];&lt;br /&gt;
&lt;br /&gt;
        return preferred || children.sort(function (a, b) {&lt;br /&gt;
            return (b.textContent || &#039;&#039;).trim().length - (a.textContent || &#039;&#039;).trim().length;&lt;br /&gt;
        })[0] || null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getSystemDocRawUrlForShell() {&lt;br /&gt;
        var title = mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.util &amp;amp;&amp;amp; typeof mw.util.getUrl === &#039;function&#039;) {&lt;br /&gt;
            return mw.util.getUrl(title, {&lt;br /&gt;
                action: &#039;raw&#039;,&lt;br /&gt;
                ctype: &#039;text/plain&#039;,&lt;br /&gt;
                _: String(Date.now())&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &#039;/index.php?title=&#039; + encodeURIComponent(title) + &#039;&amp;amp;action=raw&amp;amp;ctype=text/plain&amp;amp;_=&#039; + Date.now();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocSourceViewerForShell() {&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (viewer &amp;amp;&amp;amp; viewer.parentNode) {&lt;br /&gt;
            viewer.parentNode.removeChild(viewer);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-original-source-hidden&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-source-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySystemDocSourceViewerLayoutForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
        var indicator = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
        var bottomNav = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
        var viewerTop;&lt;br /&gt;
        var mainBottom;&lt;br /&gt;
        var viewerHeight;&lt;br /&gt;
        var currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (!output || !main || !viewer || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
        output.style.setProperty(&#039;display&#039;, &#039;flex&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;flex-direction&#039;, &#039;column&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;height&#039;, &#039;auto&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;position&#039;, &#039;relative&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        Array.prototype.slice.call(output.children || []).forEach(function (el) {&lt;br /&gt;
            if (!el || el === viewer || el === indicator) return;&lt;br /&gt;
            el.style.setProperty(&#039;flex&#039;, &#039;0 0 auto&#039;, &#039;important&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        main.style.setProperty(&#039;display&#039;, &#039;flex&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;flex-direction&#039;, &#039;column&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        viewer.style.setProperty(&#039;display&#039;, &#039;block&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;box-sizing&#039;, &#039;border-box&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;flex&#039;, &#039;0 0 auto&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;width&#039;, &#039;100%&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;max-width&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;margin&#039;, &#039;8px 0 0&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;padding&#039;, &#039;8px 10px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;overflow&#039;, &#039;auto&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;background&#039;, &#039;#f3f6f7&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;color&#039;, &#039;#111111&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;border&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;outline&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;font-family&#039;, &amp;quot;Consolas, Monaco, &#039;Courier New&#039;, monospace&amp;quot;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;font-size&#039;, &#039;12px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;line-height&#039;, &#039;1.45&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;white-space&#039;, &#039;pre&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;tab-size&#039;, &#039;4&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;scrollbar-gutter&#039;, &#039;stable&#039;);&lt;br /&gt;
&lt;br /&gt;
        viewerTop = viewer.getBoundingClientRect().top;&lt;br /&gt;
        mainBottom = main.getBoundingClientRect().bottom;&lt;br /&gt;
&lt;br /&gt;
        if (bottomNav) {&lt;br /&gt;
            mainBottom = Math.min(mainBottom, bottomNav.getBoundingClientRect().top - 8);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        viewerHeight = Math.max(260, Math.round(mainBottom - viewerTop));&lt;br /&gt;
&lt;br /&gt;
        viewer.style.setProperty(&#039;height&#039;, viewerHeight + &#039;px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.style.setProperty(&#039;max-height&#039;, viewerHeight + &#039;px&#039;, &#039;important&#039;);&lt;br /&gt;
        viewer.scrollTop = currentScrollTop;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocSourceViewerForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var source;&lt;br /&gt;
        var viewer;&lt;br /&gt;
        var fallbackText;&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var token;&lt;br /&gt;
        var currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (!output || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        cleanupLegacySystemDocCodeMutationsForShell();&lt;br /&gt;
&lt;br /&gt;
        source = findSystemDocSourceNodeForShell();&lt;br /&gt;
        if (!source) return;&lt;br /&gt;
&lt;br /&gt;
        viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
        fallbackText = source.textContent || &#039;&#039;;&lt;br /&gt;
        pageName = String(mw.config.get(&#039;wgPageName&#039;) || readCurrentPageNameForShell());&lt;br /&gt;
&lt;br /&gt;
        if (!viewer) {&lt;br /&gt;
            viewer = document.createElement(&#039;pre&#039;);&lt;br /&gt;
            viewer.id = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            viewer.className = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            output.insertBefore(viewer, source);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
        if (!viewer.textContent &amp;amp;&amp;amp; fallbackText) {&lt;br /&gt;
            viewer.textContent = fallbackText;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        source.classList.add(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
        source.setAttribute(&#039;data-clbi-system-source-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        source.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        applySystemDocSourceViewerLayoutForShell();&lt;br /&gt;
        viewer.scrollTop = currentScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (viewer.getAttribute(&#039;data-clbi-raw-title&#039;) === pageName &amp;amp;&amp;amp; viewer.getAttribute(&#039;data-clbi-raw-loaded&#039;) === &#039;1&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        viewer.setAttribute(&#039;data-clbi-raw-title&#039;, pageName);&lt;br /&gt;
        token = ++systemDocRawFetchToken;&lt;br /&gt;
&lt;br /&gt;
        fetch(getSystemDocRawUrlForShell(), { credentials: &#039;same-origin&#039; })&lt;br /&gt;
            .then(function (res) {&lt;br /&gt;
                if (!res.ok) throw new Error(&#039;raw fetch failed &#039; + res.status);&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function (text) {&lt;br /&gt;
                if (token !== systemDocRawFetchToken) return;&lt;br /&gt;
&lt;br /&gt;
                currentScrollTop = viewer.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
                if (text &amp;amp;&amp;amp; viewer.textContent !== text) {&lt;br /&gt;
                    viewer.textContent = text;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;1&#039;);&lt;br /&gt;
                applySystemDocSourceViewerLayoutForShell();&lt;br /&gt;
                viewer.scrollTop = currentScrollTop;&lt;br /&gt;
            })&lt;br /&gt;
            .catch(function () {&lt;br /&gt;
                viewer.setAttribute(&#039;data-clbi-raw-loaded&#039;, &#039;0&#039;);&lt;br /&gt;
                applySystemDocSourceViewerLayoutForShell();&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
        var existing;&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) { existing.parentNode.removeChild(existing); }&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.createElement(&#039;div&#039;);&lt;br /&gt;
        row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
        row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
        box = document.createElement(&#039;div&#039;);&lt;br /&gt;
        box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
        meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
        meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
        label = document.createElement(&#039;span&#039;);&lt;br /&gt;
        label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
        label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
        type = document.createElement(&#039;span&#039;);&lt;br /&gt;
        type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
        type.textContent = ext;&lt;br /&gt;
&lt;br /&gt;
        title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
        title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        meta.appendChild(label);&lt;br /&gt;
        meta.appendChild(type);&lt;br /&gt;
        box.appendChild(meta);&lt;br /&gt;
        box.appendChild(title);&lt;br /&gt;
        row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
        anchor = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
            anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
        } else if (main) {&lt;br /&gt;
            main.insertBefore(row, main.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        renderSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            removeSystemDocIndicatorForShell();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;resize&#039;, function () {&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            window.setTimeout(applySystemDocSourceViewerLayoutForShell, 0);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        renderSystemDocSourceViewer: renderSystemDocSourceViewerForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell,&lt;br /&gt;
        refreshSystemDocSourceViewer: renderSystemDocSourceViewerForShell,&lt;br /&gt;
        layoutSystemDocSourceViewer: applySystemDocSourceViewerLayoutForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2464</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2464"/>
		<updated>2026-06-02T20:01:18Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
MediaWiki CSS/JS 문서는 기본 제목을 숨기고 우상단 시스템 문서 표식만 띄운다.&lt;br /&gt;
캐시 안내문은 유지한다.&lt;br /&gt;
원본 SyntaxHighlight 출력은 숨기고, Common.js가 만든 읽기 전용 raw viewer만 스크롤한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; :not(#clbi-system-source-viewer):not(#clbi-system-doc-indicator-row) {&lt;br /&gt;
flex:0 0 auto !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-original-source-hidden {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page #clbi-system-source-viewer {&lt;br /&gt;
display:block !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:8px 0 0 !important;&lt;br /&gt;
padding:8px 10px !important;&lt;br /&gt;
overflow:auto !important;&lt;br /&gt;
background:#f3f6f7 !important;&lt;br /&gt;
color:#111111 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
outline:none !important;&lt;br /&gt;
font-family:Consolas, Monaco, &#039;Courier New&#039;, monospace !important;&lt;br /&gt;
font-size:12px !important;&lt;br /&gt;
line-height:1.45 !important;&lt;br /&gt;
white-space:pre !important;&lt;br /&gt;
tab-size:4;&lt;br /&gt;
scrollbar-gutter:stable;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:8px !important;&lt;br /&gt;
right:8px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 16px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
max-width:520px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:7px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:0.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
max-width:500px !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:24px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:0.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78) !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
word-break:normal !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2463</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2463"/>
		<updated>2026-06-02T14:07:10Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    function findSystemDocSourceNodeForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var children;&lt;br /&gt;
        var preferred;&lt;br /&gt;
&lt;br /&gt;
        if (!output) return null;&lt;br /&gt;
&lt;br /&gt;
        children = Array.prototype.slice.call(output.children || [])&lt;br /&gt;
            .filter(function (el) {&lt;br /&gt;
                return el &amp;amp;&amp;amp; el.nodeType === 1 &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-doc-indicator-row&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-source-viewer&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    !el.classList.contains(&#039;catlinks&#039;) &amp;amp;&amp;amp;&lt;br /&gt;
                    (el.textContent || &#039;&#039;).trim().length &amp;gt; 200;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        preferred = children.filter(function (el) {&lt;br /&gt;
            return el.matches &amp;amp;&amp;amp; el.matches(&#039;.mw-highlight, .mw-code, pre&#039;);&lt;br /&gt;
        })[0];&lt;br /&gt;
&lt;br /&gt;
        return preferred || children.sort(function (a, b) {&lt;br /&gt;
            return (b.textContent || &#039;&#039;).trim().length - (a.textContent || &#039;&#039;).trim().length;&lt;br /&gt;
        })[0] || null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocSourceViewerForShell() {&lt;br /&gt;
        var viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (viewer &amp;amp;&amp;amp; viewer.parentNode) {&lt;br /&gt;
            viewer.parentNode.removeChild(viewer);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-original-source-hidden&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-source-hidden&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocSourceViewerForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var source;&lt;br /&gt;
        var viewer;&lt;br /&gt;
        var text;&lt;br /&gt;
        var previousScrollTop;&lt;br /&gt;
&lt;br /&gt;
        if (!output || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        source = findSystemDocSourceNodeForShell();&lt;br /&gt;
        if (!source) return;&lt;br /&gt;
&lt;br /&gt;
        text = source.textContent || &#039;&#039;;&lt;br /&gt;
        viewer = document.getElementById(&#039;clbi-system-source-viewer&#039;);&lt;br /&gt;
        previousScrollTop = viewer ? viewer.scrollTop : 0;&lt;br /&gt;
&lt;br /&gt;
        if (!viewer) {&lt;br /&gt;
            viewer = document.createElement(&#039;pre&#039;);&lt;br /&gt;
            viewer.id = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            viewer.className = &#039;clbi-system-source-viewer&#039;;&lt;br /&gt;
            output.insertBefore(viewer, source);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (viewer.textContent !== text) {&lt;br /&gt;
            viewer.textContent = text;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        source.classList.add(&#039;clbi-system-original-source-hidden&#039;);&lt;br /&gt;
        source.setAttribute(&#039;data-clbi-system-source-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        viewer.scrollTop = previousScrollTop;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
        var existing;&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) { existing.parentNode.removeChild(existing); }&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.createElement(&#039;div&#039;);&lt;br /&gt;
        row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
        row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
        box = document.createElement(&#039;div&#039;);&lt;br /&gt;
        box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
        meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
        meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
        label = document.createElement(&#039;span&#039;);&lt;br /&gt;
        label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
        label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
        type = document.createElement(&#039;span&#039;);&lt;br /&gt;
        type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
        type.textContent = ext;&lt;br /&gt;
&lt;br /&gt;
        title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
        title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        meta.appendChild(label);&lt;br /&gt;
        meta.appendChild(type);&lt;br /&gt;
        box.appendChild(meta);&lt;br /&gt;
        box.appendChild(title);&lt;br /&gt;
        row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
        anchor = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
            anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
        } else if (main) {&lt;br /&gt;
            main.insertBefore(row, main.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        renderSystemDocSourceViewerForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            removeSystemDocIndicatorForShell();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        renderSystemDocSourceViewer: renderSystemDocSourceViewerForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2462</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2462"/>
		<updated>2026-06-02T14:07:01Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
MediaWiki CSS/JS 문서는 기본 제목을 숨기고 우상단 문서명 표식만 띄운다.&lt;br /&gt;
실제 소스는 MediaWiki가 만든 SyntaxHighlight DOM을 직접 쓰지 않고,&lt;br /&gt;
Common.js가 만든 읽기 전용 pre 소스 뷰어에서 표시한다.&lt;br /&gt;
- 캐시 안내문은 유지한다.&lt;br /&gt;
- 문서명 표식은 absolute 오버레이이므로 본문 흐름을 차지하지 않는다.&lt;br /&gt;
- 소스 뷰어만 내부 스크롤 영역이 된다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; :not(.clbi-system-source-viewer):not(#clbi-system-doc-indicator-row) {&lt;br /&gt;
flex:0 0 auto !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-original-source-hidden {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-source-viewer {&lt;br /&gt;
display:block !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
margin:8px 0 0 !important;&lt;br /&gt;
padding:8px 10px !important;&lt;br /&gt;
overflow:auto !important;&lt;br /&gt;
background:#f3f6f7 !important;&lt;br /&gt;
color:#111111 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
outline:none !important;&lt;br /&gt;
font-family:Consolas, Monaco, &#039;Courier New&#039;, monospace !important;&lt;br /&gt;
font-size:12px !important;&lt;br /&gt;
line-height:1.45 !important;&lt;br /&gt;
white-space:pre !important;&lt;br /&gt;
tab-size:4;&lt;br /&gt;
scrollbar-gutter:stable;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:8px !important;&lt;br /&gt;
right:8px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 16px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
max-width:520px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:7px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:0.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
max-width:500px !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:24px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:0.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78) !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
word-break:normal !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2461</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2461"/>
		<updated>2026-06-02T13:39:52Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    function applySystemDocMeasuredScrollForShell() {&lt;br /&gt;
        var gap = 8;&lt;br /&gt;
        var topNav = document.querySelector(&#039;#clbi-top-nav-wrap&#039;);&lt;br /&gt;
        var bottomNav = document.querySelector(&#039;#clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
        var wrapper = document.querySelector(&#039;.content-wrapper&#039;);&lt;br /&gt;
        var liberty = document.querySelector(&#039;.container-fluid.liberty-content&#039;);&lt;br /&gt;
        var main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var children;&lt;br /&gt;
        var target;&lt;br /&gt;
        var topBottom;&lt;br /&gt;
        var bottomTop;&lt;br /&gt;
        var wrapperTop;&lt;br /&gt;
        var wrapperHeight;&lt;br /&gt;
        var codeTop;&lt;br /&gt;
        var codeHeight;&lt;br /&gt;
        var savedScroll;&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
        if (!topNav || !bottomNav || !wrapper || !liberty || !main || !output) return;&lt;br /&gt;
&lt;br /&gt;
        children = Array.prototype.slice.call(output.children || []);&lt;br /&gt;
        target = children&lt;br /&gt;
            .filter(function (el) {&lt;br /&gt;
                return el &amp;amp;&amp;amp;&lt;br /&gt;
                    el.nodeType === 1 &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-doc-indicator-row&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    !el.classList.contains(&#039;catlinks&#039;) &amp;amp;&amp;amp;&lt;br /&gt;
                    (el.textContent || &#039;&#039;).trim().length &amp;gt; 200;&lt;br /&gt;
            })&lt;br /&gt;
            .map(function (el) {&lt;br /&gt;
                return {&lt;br /&gt;
                    el: el,&lt;br /&gt;
                    length: (el.textContent || &#039;&#039;).trim().length&lt;br /&gt;
                };&lt;br /&gt;
            })&lt;br /&gt;
            .sort(function (a, b) {&lt;br /&gt;
                return b.length - a.length;&lt;br /&gt;
            })[0];&lt;br /&gt;
&lt;br /&gt;
        if (!target || !target.el) return;&lt;br /&gt;
        target = target.el;&lt;br /&gt;
        savedScroll = target.scrollTop || 0;&lt;br /&gt;
&lt;br /&gt;
        topBottom = topNav.getBoundingClientRect().bottom;&lt;br /&gt;
        bottomTop = bottomNav.getBoundingClientRect().top;&lt;br /&gt;
        wrapperTop = Math.round(topBottom + gap);&lt;br /&gt;
        wrapperHeight = Math.max(240, Math.round(bottomTop - wrapperTop - gap));&lt;br /&gt;
&lt;br /&gt;
        wrapper.style.setProperty(&#039;height&#039;, wrapperHeight + &#039;px&#039;, &#039;important&#039;);&lt;br /&gt;
        wrapper.style.setProperty(&#039;max-height&#039;, wrapperHeight + &#039;px&#039;, &#039;important&#039;);&lt;br /&gt;
        wrapper.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        wrapper.style.setProperty(&#039;overflow&#039;, &#039;visible&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        liberty.style.setProperty(&#039;height&#039;, &#039;calc(100% + 14px)&#039;, &#039;important&#039;);&lt;br /&gt;
        liberty.style.setProperty(&#039;max-height&#039;, &#039;calc(100% + 14px)&#039;, &#039;important&#039;);&lt;br /&gt;
        liberty.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        liberty.style.setProperty(&#039;display&#039;, &#039;flex&#039;, &#039;important&#039;);&lt;br /&gt;
        liberty.style.setProperty(&#039;flex-direction&#039;, &#039;column&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.style.setProperty(&#039;height&#039;, &#039;100%&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;display&#039;, &#039;flex&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;flex-direction&#039;, &#039;column&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        output.style.setProperty(&#039;display&#039;, &#039;flex&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;flex-direction&#039;, &#039;column&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;flex&#039;, &#039;1 1 auto&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;height&#039;, &#039;auto&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;position&#039;, &#039;relative&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        children.forEach(function (el) {&lt;br /&gt;
            if (el === target) return;&lt;br /&gt;
            el.style.setProperty(&#039;flex&#039;, &#039;0 0 auto&#039;, &#039;important&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        codeTop = target.getBoundingClientRect().top;&lt;br /&gt;
        codeHeight = Math.max(220, Math.round(main.getBoundingClientRect().bottom - codeTop - gap));&lt;br /&gt;
&lt;br /&gt;
        target.style.setProperty(&#039;display&#039;, &#039;block&#039;, &#039;important&#039;);&lt;br /&gt;
        target.style.setProperty(&#039;box-sizing&#039;, &#039;border-box&#039;, &#039;important&#039;);&lt;br /&gt;
        target.style.setProperty(&#039;flex&#039;, &#039;1 1 0&#039;, &#039;important&#039;);&lt;br /&gt;
        target.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        target.style.setProperty(&#039;height&#039;, codeHeight + &#039;px&#039;, &#039;important&#039;);&lt;br /&gt;
        target.style.setProperty(&#039;max-height&#039;, codeHeight + &#039;px&#039;, &#039;important&#039;);&lt;br /&gt;
        target.style.setProperty(&#039;overflow&#039;, &#039;auto&#039;, &#039;important&#039;);&lt;br /&gt;
        target.style.setProperty(&#039;margin&#039;, &#039;8px 0 0&#039;, &#039;important&#039;);&lt;br /&gt;
        target.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        target.style.setProperty(&#039;background&#039;, &#039;#f3f6f7&#039;, &#039;important&#039;);&lt;br /&gt;
        target.style.setProperty(&#039;color&#039;, &#039;#111111&#039;, &#039;important&#039;);&lt;br /&gt;
        target.style.setProperty(&#039;scrollbar-gutter&#039;, &#039;stable&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        target.querySelectorAll(&#039;pre, code&#039;).forEach(function (el) {&lt;br /&gt;
            el.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            el.style.setProperty(&#039;max-width&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        target.scrollTop = savedScroll;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function scheduleSystemDocMeasuredScrollForShell() {&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
        window.requestAnimationFrame(function () {&lt;br /&gt;
            applySystemDocMeasuredScrollForShell();&lt;br /&gt;
        });&lt;br /&gt;
        window.setTimeout(applySystemDocMeasuredScrollForShell, 80);&lt;br /&gt;
        window.setTimeout(applySystemDocMeasuredScrollForShell, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocIndicatorForShell();&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.createElement(&#039;div&#039;);&lt;br /&gt;
        row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
        row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
        box = document.createElement(&#039;div&#039;);&lt;br /&gt;
        box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
        meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
        meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
        label = document.createElement(&#039;span&#039;);&lt;br /&gt;
        label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
        label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
        type = document.createElement(&#039;span&#039;);&lt;br /&gt;
        type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
        type.textContent = ext;&lt;br /&gt;
&lt;br /&gt;
        title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
        title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        meta.appendChild(label);&lt;br /&gt;
        meta.appendChild(type);&lt;br /&gt;
        box.appendChild(meta);&lt;br /&gt;
        box.appendChild(title);&lt;br /&gt;
        row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
        anchor = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
            anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
        } else if (main) {&lt;br /&gt;
            main.insertBefore(row, main.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        scheduleSystemDocMeasuredScrollForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        removeSystemDocIndicatorForShell();&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        applySystemDocMeasuredScroll: applySystemDocMeasuredScrollForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2460</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2460"/>
		<updated>2026-06-02T13:39:44Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
시스템 CSS/JS 문서의 기본 제목은 숨기고 우상단 문서명 표식만 띄운다.&lt;br /&gt;
이 표식은 absolute 오버레이이며, 안내문/코드 본문 흐름에 참여하지 않는다.&lt;br /&gt;
코드 영역의 실제 높이와 스크롤은 Common.js가 현재 DOM 측정값으로 인라인 적용한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:8px !important;&lt;br /&gt;
right:8px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 16px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
max-width:520px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:7px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:0.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
max-width:500px !important;text-align:right !important;&lt;br /&gt;
font-size:24px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:0.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78) !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
word-break:normal !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2459</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2459"/>
		<updated>2026-06-02T13:34:23Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocIndicatorForShell();&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.createElement(&#039;div&#039;);&lt;br /&gt;
        row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
        row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
        box = document.createElement(&#039;div&#039;);&lt;br /&gt;
        box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
        meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
        meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
        label = document.createElement(&#039;span&#039;);&lt;br /&gt;
        label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
        label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
        type = document.createElement(&#039;span&#039;);&lt;br /&gt;
        type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
        type.textContent = ext;&lt;br /&gt;
&lt;br /&gt;
        title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
        title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        meta.appendChild(label);&lt;br /&gt;
        meta.appendChild(type);&lt;br /&gt;
        box.appendChild(meta);&lt;br /&gt;
        box.appendChild(title);&lt;br /&gt;
        row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
        anchor = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
            anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
        } else if (main) {&lt;br /&gt;
            main.insertBefore(row, main.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        removeSystemDocIndicatorForShell();&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2458</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2458"/>
		<updated>2026-06-02T13:34:13Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
CSS/JS 시스템 문서는 MediaWiki 기본 제목을 숨기고 우상단 시스템 문서 표식만 띄운다.&lt;br /&gt;
캐시 안내문은 유지한다. 실제 코드 DOM은 .mw-parser-output의 직접 자식 .mw-highlight이다.&lt;br /&gt;
새 래퍼를 만들지 않고 이 실제 코드 DOM 자체를 내부 스크롤 영역으로 사용한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:8px !important;&lt;br /&gt;
right:8px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 16px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
max-width:520px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:7px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:0.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:22px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:0.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78) !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
word-break:normal !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
max-width:500px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; :not(.mw-highlight):not(.mw-code):not(pre):not(#clbi-system-doc-indicator-row) {&lt;br /&gt;
flex:0 0 auto !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; .mw-highlight,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; .mw-code,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; pre {&lt;br /&gt;
display:block !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
margin:8px 0 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:auto !important;&lt;br /&gt;
background:#f3f6f7 !important;&lt;br /&gt;
color:#111111 !important;&lt;br /&gt;
scrollbar-gutter:stable;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; .mw-highlight pre,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; .mw-code pre,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; pre {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2457</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2457"/>
		<updated>2026-06-02T13:30:14Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    function clearSystemDocCodeboxForShell() {&lt;br /&gt;
        var nodes = document.querySelectorAll(&#039;.clbi-system-doc-codebox&#039;);&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-doc-codebox&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;box-sizing&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;flex&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;background&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;color&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySystemDocCodeboxForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var children;&lt;br /&gt;
        var target;&lt;br /&gt;
        var scrollTop;&lt;br /&gt;
&lt;br /&gt;
        clearSystemDocCodeboxForShell();&lt;br /&gt;
&lt;br /&gt;
        if (!output || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        children = Array.prototype.slice.call(output.children || []);&lt;br /&gt;
        target = children&lt;br /&gt;
            .filter(function (el) {&lt;br /&gt;
                return el &amp;amp;&amp;amp; el.nodeType === 1 &amp;amp;&amp;amp;&lt;br /&gt;
                    el.id !== &#039;clbi-system-doc-indicator-row&#039; &amp;amp;&amp;amp;&lt;br /&gt;
                    !el.classList.contains(&#039;catlinks&#039;) &amp;amp;&amp;amp;&lt;br /&gt;
                    (el.textContent || &#039;&#039;).trim().length &amp;gt; 200;&lt;br /&gt;
            })&lt;br /&gt;
            .map(function (el) {&lt;br /&gt;
                return {&lt;br /&gt;
                    el: el,&lt;br /&gt;
                    length: (el.textContent || &#039;&#039;).trim().length&lt;br /&gt;
                };&lt;br /&gt;
            })&lt;br /&gt;
            .sort(function (a, b) {&lt;br /&gt;
                return b.length - a.length;&lt;br /&gt;
            })[0];&lt;br /&gt;
&lt;br /&gt;
        if (!target || !target.el) return;&lt;br /&gt;
&lt;br /&gt;
        scrollTop = target.el.scrollTop || 0;&lt;br /&gt;
        target.el.classList.add(&#039;clbi-system-doc-codebox&#039;);&lt;br /&gt;
        target.el.setAttribute(&#039;data-clbi-system-doc-codebox&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        CSS만으로는 MediaWiki 코드 렌더러의 실제 출력 DOM이 버전별로 흔들린다.&lt;br /&gt;
        콘솔 검증 결과, 현재 코드 본문은 .mw-parser-output의 직접 자식 .mw-highlight다.&lt;br /&gt;
        새 래퍼를 만들지 않고 실제 코드 DOM 자체를 스크롤 박스로 고정한다.&lt;br /&gt;
        */&lt;br /&gt;
        output.style.setProperty(&#039;display&#039;, &#039;flex&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;flex-direction&#039;, &#039;column&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        children.forEach(function (el) {&lt;br /&gt;
            if (el === target.el) return;&lt;br /&gt;
            el.style.setProperty(&#039;flex&#039;, &#039;0 0 auto&#039;, &#039;important&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        target.el.style.setProperty(&#039;display&#039;, &#039;block&#039;, &#039;important&#039;);&lt;br /&gt;
        target.el.style.setProperty(&#039;box-sizing&#039;, &#039;border-box&#039;, &#039;important&#039;);&lt;br /&gt;
        target.el.style.setProperty(&#039;flex&#039;, &#039;1 1 0&#039;, &#039;important&#039;);&lt;br /&gt;
        target.el.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        target.el.style.setProperty(&#039;height&#039;, &#039;auto&#039;, &#039;important&#039;);&lt;br /&gt;
        target.el.style.setProperty(&#039;overflow&#039;, &#039;auto&#039;, &#039;important&#039;);&lt;br /&gt;
        target.el.style.setProperty(&#039;margin&#039;, &#039;8px 0 0&#039;, &#039;important&#039;);&lt;br /&gt;
        target.el.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        target.el.style.setProperty(&#039;background&#039;, &#039;#f3f6f7&#039;, &#039;important&#039;);&lt;br /&gt;
        target.el.style.setProperty(&#039;color&#039;, &#039;#111&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        target.el.querySelectorAll(&#039;pre, code&#039;).forEach(function (node) {&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;max-width&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (scrollTop) {&lt;br /&gt;
            target.el.scrollTop = scrollTop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocIndicatorForShell();&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.createElement(&#039;div&#039;);&lt;br /&gt;
        row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
        row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
        box = document.createElement(&#039;div&#039;);&lt;br /&gt;
        box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
        meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
        meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
        label = document.createElement(&#039;span&#039;);&lt;br /&gt;
        label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
        label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
        type = document.createElement(&#039;span&#039;);&lt;br /&gt;
        type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
        type.textContent = ext;&lt;br /&gt;
&lt;br /&gt;
        title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
        title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        meta.appendChild(label);&lt;br /&gt;
        meta.appendChild(type);&lt;br /&gt;
        box.appendChild(meta);&lt;br /&gt;
        box.appendChild(title);&lt;br /&gt;
        row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
        anchor = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
            anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
        } else if (main) {&lt;br /&gt;
            main.insertBefore(row, main.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        applySystemDocCodeboxForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        removeSystemDocIndicatorForShell();&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2456</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2456"/>
		<updated>2026-06-02T13:30:06Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/* CSS/JS 문서는 기본 제목을 숨기고 우상단 시스템 문서 표식만 띄운다. */&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:8px !important;&lt;br /&gt;
right:8px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 16px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
max-width:560px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:7px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:0.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
max-width:520px !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:24px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:0.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 실제 코드 DOM 자체에 붙는 클래스다. 새 래퍼를 만들지 않는다. */&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; :not(.clbi-system-doc-codebox) {&lt;br /&gt;
flex:0 0 auto !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codebox {&lt;br /&gt;
display:block !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
overflow:auto !important;&lt;br /&gt;
margin:8px 0 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
background:#f3f6f7 !important;&lt;br /&gt;
color:#111 !important;&lt;br /&gt;
scrollbar-gutter:stable;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codebox pre,&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codebox code {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2455</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2455"/>
		<updated>2026-06-02T13:26:23Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
    var lastSystemDocPageKey = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) ||&lt;br /&gt;
                contentModel === &#039;css&#039; ||&lt;br /&gt;
                contentModel === &#039;javascript&#039; ||&lt;br /&gt;
                contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resetSystemDocRuntimeStyles() {&lt;br /&gt;
        document.querySelectorAll(&#039;[data-clbi-system-doc-style=&amp;quot;1&amp;quot;]&#039;).forEach(function (node) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-doc-style&#039;);&lt;br /&gt;
            node.removeAttribute(&#039;style&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        lastSystemDocPageKey = &#039;&#039;;&lt;br /&gt;
        resetSystemDocRuntimeStyles();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var main;&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
        main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!row) {&lt;br /&gt;
            row = document.createElement(&#039;div&#039;);&lt;br /&gt;
            row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
            row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
            box = document.createElement(&#039;div&#039;);&lt;br /&gt;
            box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
            meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
            label = document.createElement(&#039;span&#039;);&lt;br /&gt;
            label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
            label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
            type = document.createElement(&#039;span&#039;);&lt;br /&gt;
            type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
&lt;br /&gt;
            title = document.createElement(&#039;div&#039;);&lt;br /&gt;
            title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta.appendChild(label);&lt;br /&gt;
            meta.appendChild(type);&lt;br /&gt;
            box.appendChild(meta);&lt;br /&gt;
            box.appendChild(title);&lt;br /&gt;
            row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
            if (main) {&lt;br /&gt;
                main.insertBefore(row, main.firstChild);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        type = row.querySelector(&#039;.clbi-system-doc-type&#039;);&lt;br /&gt;
        title = row.querySelector(&#039;.clbi-system-doc-title&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (type) type.textContent = ext;&lt;br /&gt;
        if (title) title.textContent = pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setImportantStyle(node, prop, value) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
        node.setAttribute(&#039;data-clbi-system-doc-style&#039;, &#039;1&#039;);&lt;br /&gt;
        node.style.setProperty(prop, value, &#039;important&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySystemDocCodeScrollForShell() {&lt;br /&gt;
        var output;&lt;br /&gt;
        var main;&lt;br /&gt;
        var bottom;&lt;br /&gt;
        var children;&lt;br /&gt;
        var target;&lt;br /&gt;
        var targetLen = 0;&lt;br /&gt;
        var savedScrollTop;&lt;br /&gt;
        var savedScrollLeft;&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
        bottom = document.querySelector(&#039;#clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!output || !main || !bottom) return;&lt;br /&gt;
&lt;br /&gt;
        children = Array.prototype.slice.call(output.children || []);&lt;br /&gt;
&lt;br /&gt;
        children.forEach(function (node) {&lt;br /&gt;
            var length;&lt;br /&gt;
&lt;br /&gt;
            if (!node || node.id === &#039;clbi-system-doc-indicator-row&#039;) return;&lt;br /&gt;
&lt;br /&gt;
            length = String(node.textContent || &#039;&#039;).trim().length;&lt;br /&gt;
&lt;br /&gt;
            if (length &amp;gt; targetLen) {&lt;br /&gt;
                target = node;&lt;br /&gt;
                targetLen = length;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!target || targetLen &amp;lt; 200) return;&lt;br /&gt;
&lt;br /&gt;
        savedScrollTop = target.scrollTop || 0;&lt;br /&gt;
        savedScrollLeft = target.scrollLeft || 0;&lt;br /&gt;
&lt;br /&gt;
        setImportantStyle(output, &#039;display&#039;, &#039;flex&#039;);&lt;br /&gt;
        setImportantStyle(output, &#039;flex-direction&#039;, &#039;column&#039;);&lt;br /&gt;
        setImportantStyle(output, &#039;overflow&#039;, &#039;hidden&#039;);&lt;br /&gt;
        setImportantStyle(output, &#039;min-height&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        children.forEach(function (node) {&lt;br /&gt;
            if (node === target || node.id === &#039;clbi-system-doc-indicator-row&#039;) return;&lt;br /&gt;
            setImportantStyle(node, &#039;flex&#039;, &#039;0 0 auto&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setImportantStyle(target, &#039;display&#039;, &#039;block&#039;);&lt;br /&gt;
        setImportantStyle(target, &#039;box-sizing&#039;, &#039;border-box&#039;);&lt;br /&gt;
        setImportantStyle(target, &#039;flex&#039;, &#039;1 1 0&#039;);&lt;br /&gt;
        setImportantStyle(target, &#039;min-height&#039;, &#039;0&#039;);&lt;br /&gt;
        setImportantStyle(target, &#039;height&#039;, &#039;auto&#039;);&lt;br /&gt;
        setImportantStyle(target, &#039;overflow&#039;, &#039;auto&#039;);&lt;br /&gt;
        setImportantStyle(target, &#039;margin&#039;, &#039;8px 0 0&#039;);&lt;br /&gt;
        setImportantStyle(target, &#039;padding&#039;, &#039;0&#039;);&lt;br /&gt;
        setImportantStyle(target, &#039;background&#039;, &#039;#f3f6f7&#039;);&lt;br /&gt;
        setImportantStyle(target, &#039;color&#039;, &#039;#111&#039;);&lt;br /&gt;
&lt;br /&gt;
        target.querySelectorAll(&#039;pre, code&#039;).forEach(function (node) {&lt;br /&gt;
            setImportantStyle(node, &#039;margin&#039;, &#039;0&#039;);&lt;br /&gt;
            setImportantStyle(node, &#039;max-width&#039;, &#039;none&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (savedScrollTop || savedScrollLeft) {&lt;br /&gt;
            target.scrollTop = savedScrollTop;&lt;br /&gt;
            target.scrollLeft = savedScrollLeft;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
            applySystemDocCodeScrollForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            removeSystemDocIndicatorForShell();&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            removeSystemDocIndicatorForShell();&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 120);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 450);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell,&lt;br /&gt;
        applySystemDocCodeScroll: applySystemDocCodeScrollForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2454</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2454"/>
		<updated>2026-06-02T13:26:12Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/* CSS/JS 문서는 기본 제목을 숨기고 우상단 시스템 문서 표식만 띄운다. */&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:8px !important;&lt;br /&gt;
right:8px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 16px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
max-width:560px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:7px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:0.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
max-width:520px !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:24px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:0.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2453</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2453"/>
		<updated>2026-06-02T13:14:56Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function unmarkSystemDocCodeBoxForShell() {&lt;br /&gt;
        document.querySelectorAll(&#039;.clbi-system-doc-codebox&#039;).forEach(function (node) {&lt;br /&gt;
            node.classList.remove(&#039;clbi-system-doc-codebox&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function markSystemDocCodeBoxForShell() {&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var candidates;&lt;br /&gt;
        var best = null;&lt;br /&gt;
        var bestLength = 0;&lt;br /&gt;
        var codeBox;&lt;br /&gt;
&lt;br /&gt;
        if (!output || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        candidates = Array.prototype.slice.call(output.querySelectorAll(&#039;.mw-highlight, .mw-code, pre&#039;));&lt;br /&gt;
&lt;br /&gt;
        candidates.forEach(function (node) {&lt;br /&gt;
            var length;&lt;br /&gt;
            if (!node || node.closest(&#039;#clbi-system-doc-indicator-row&#039;)) return;&lt;br /&gt;
            length = String(node.textContent || &#039;&#039;).trim().length;&lt;br /&gt;
            if (length &amp;gt; bestLength) {&lt;br /&gt;
                best = node;&lt;br /&gt;
                bestLength = length;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        unmarkSystemDocCodeBoxForShell();&lt;br /&gt;
        if (!best || bestLength &amp;lt; 200) return;&lt;br /&gt;
&lt;br /&gt;
        codeBox = best;&lt;br /&gt;
        while (codeBox.parentElement &amp;amp;&amp;amp; codeBox.parentElement !== output) {&lt;br /&gt;
            codeBox = codeBox.parentElement;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!codeBox || codeBox === output) {&lt;br /&gt;
            codeBox = best;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        codeBox.classList.add(&#039;clbi-system-doc-codebox&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        unmarkSystemDocCodeBoxForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var main;&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
        main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!row) {&lt;br /&gt;
            row = document.createElement(&#039;div&#039;);&lt;br /&gt;
            row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
            row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
            box = document.createElement(&#039;div&#039;);&lt;br /&gt;
            box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
            meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
            label = document.createElement(&#039;span&#039;);&lt;br /&gt;
            label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
            label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
            type = document.createElement(&#039;span&#039;);&lt;br /&gt;
            type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
&lt;br /&gt;
            title = document.createElement(&#039;div&#039;);&lt;br /&gt;
            title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
&lt;br /&gt;
            meta.appendChild(label);&lt;br /&gt;
            meta.appendChild(type);&lt;br /&gt;
            box.appendChild(meta);&lt;br /&gt;
            box.appendChild(title);&lt;br /&gt;
            row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
            if (main) {&lt;br /&gt;
                main.insertBefore(row, main.firstChild);&lt;br /&gt;
            } else {&lt;br /&gt;
                document.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        type = row.querySelector(&#039;.clbi-system-doc-type&#039;);&lt;br /&gt;
        title = row.querySelector(&#039;.clbi-system-doc-title&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (type) type.textContent = ext;&lt;br /&gt;
        if (title) title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        markSystemDocCodeBoxForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            removeSystemDocIndicatorForShell();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2452</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2452"/>
		<updated>2026-06-02T13:14:40Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
MediaWiki CSS/JS 문서는 기본 제목만 숨기고, 문서명은 우상단 오버레이로 표시한다.&lt;br /&gt;
캐시 안내문은 원래 문서 안내로 유지한다.&lt;br /&gt;
코드 출력 영역은 JS가 실제 코드 DOM에 .clbi-system-doc-codebox를 붙이고,&lt;br /&gt;
그 요소가 내부 스크롤을 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; :not(.clbi-system-doc-codebox):not(#clbi-system-doc-indicator-row) {&lt;br /&gt;
flex:0 0 auto !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codebox {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
margin:8px 0 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:auto !important;&lt;br /&gt;
background:#f3f6f7 !important;&lt;br /&gt;
color:#111111 !important;&lt;br /&gt;
scrollbar-gutter:stable;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codebox pre,&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codebox code,&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codebox .mw-code,&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codebox .mw-highlight {&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codebox pre {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:8px !important;&lt;br /&gt;
right:8px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 16px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
max-width:520px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:7px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:0.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:22px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:0.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78) !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
word-break:normal !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
max-width:500px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2451</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2451"/>
		<updated>2026-06-01T21:37:33Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
function unwrapSystemDocCodePaneForShell() {&lt;br /&gt;
        var panes = document.querySelectorAll(&#039;.clbi-system-doc-codepane&#039;);&lt;br /&gt;
&lt;br /&gt;
        panes.forEach(function (pane) {&lt;br /&gt;
            var parent;&lt;br /&gt;
            if (!pane || !pane.parentNode) return;&lt;br /&gt;
            parent = pane.parentNode;&lt;br /&gt;
            while (pane.firstChild) {&lt;br /&gt;
                parent.insertBefore(pane.firstChild, pane);&lt;br /&gt;
            }&lt;br /&gt;
            parent.removeChild(pane);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    function clearSystemDocViewportForShell() {&lt;br /&gt;
        var wrapper = document.querySelector(&#039;.content-wrapper&#039;);&lt;br /&gt;
        var liberty = document.querySelector(&#039;.container-fluid.liberty-content&#039;);&lt;br /&gt;
        var main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var nodes = [&lt;br /&gt;
            [wrapper, [&#039;height&#039;, &#039;max-height&#039;, &#039;min-height&#039;, &#039;overflow&#039;]],&lt;br /&gt;
            [liberty, [&#039;height&#039;, &#039;max-height&#039;, &#039;min-height&#039;, &#039;display&#039;, &#039;flex-direction&#039;]],&lt;br /&gt;
            [main, [&#039;height&#039;, &#039;min-height&#039;, &#039;display&#039;, &#039;flex-direction&#039;, &#039;overflow&#039;]],&lt;br /&gt;
            [output, [&#039;flex&#039;, &#039;min-height&#039;, &#039;height&#039;, &#039;overflow&#039;, &#039;position&#039;]]&lt;br /&gt;
        ];&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (item) {&lt;br /&gt;
            var node = item[0];&lt;br /&gt;
            var props = item[1];&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
            props.forEach(function (prop) {&lt;br /&gt;
                node.style.removeProperty(prop);&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;[data-clbi-system-codebox=&amp;quot;true&amp;quot;]&#039;).forEach(function (node) {&lt;br /&gt;
            [&#039;display&#039;, &#039;box-sizing&#039;, &#039;height&#039;, &#039;max-height&#039;, &#039;overflow&#039;, &#039;margin&#039;].forEach(function (prop) {&lt;br /&gt;
                node.style.removeProperty(prop);&lt;br /&gt;
            });&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-codebox&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        document.querySelectorAll(&#039;[data-clbi-system-codebox-pre=&amp;quot;true&amp;quot;]&#039;).forEach(function (node) {&lt;br /&gt;
            [&#039;margin&#039;, &#039;max-width&#039;].forEach(function (prop) {&lt;br /&gt;
                node.style.removeProperty(prop);&lt;br /&gt;
            });&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-system-codebox-pre&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function findSystemDocCodeBoxForShell(output) {&lt;br /&gt;
        var candidates;&lt;br /&gt;
        var i;&lt;br /&gt;
        var node;&lt;br /&gt;
        var text;&lt;br /&gt;
&lt;br /&gt;
        if (!output) return null;&lt;br /&gt;
&lt;br /&gt;
        candidates = Array.prototype.slice.call(output.querySelectorAll(&#039;.mw-highlight, .mw-code, pre&#039;));&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; candidates.length; i += 1) {&lt;br /&gt;
            node = candidates[i];&lt;br /&gt;
            if (!node || node.closest(&#039;#clbi-system-doc-indicator-row&#039;)) continue;&lt;br /&gt;
            text = String(node.textContent || &#039;&#039;).trim();&lt;br /&gt;
            if (text.length &amp;gt; 200) {&lt;br /&gt;
                return node.closest(&#039;.mw-highlight&#039;) || node.closest(&#039;.mw-code&#039;) || node;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySystemDocViewportForShell() {&lt;br /&gt;
        var gap = 8;&lt;br /&gt;
        var targetGap = 8;&lt;br /&gt;
        var topNav = document.querySelector(&#039;#clbi-top-nav-wrap&#039;);&lt;br /&gt;
        var bottomNav = document.querySelector(&#039;#clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
        var wrapper = document.querySelector(&#039;.content-wrapper&#039;);&lt;br /&gt;
        var liberty = document.querySelector(&#039;.container-fluid.liberty-content&#039;);&lt;br /&gt;
        var main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
        var output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        var codeBox;&lt;br /&gt;
        var topBottom;&lt;br /&gt;
        var bottomTop;&lt;br /&gt;
        var wrapperTop;&lt;br /&gt;
        var wrapperHeight;&lt;br /&gt;
        var currentGap;&lt;br /&gt;
        var correction;&lt;br /&gt;
        var codeTop;&lt;br /&gt;
        var codeHeight;&lt;br /&gt;
&lt;br /&gt;
        if (!isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            clearSystemDocViewportForShell();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        unwrapSystemDocCodePaneForShell();&lt;br /&gt;
&lt;br /&gt;
        if (!topNav || !bottomNav || !wrapper || !liberty || !main || !output) return;&lt;br /&gt;
&lt;br /&gt;
        topBottom = topNav.getBoundingClientRect().bottom;&lt;br /&gt;
        bottomTop = bottomNav.getBoundingClientRect().top;&lt;br /&gt;
        wrapperTop = Math.round(topBottom + gap);&lt;br /&gt;
        wrapperHeight = Math.max(240, Math.round(bottomTop - wrapperTop - gap));&lt;br /&gt;
&lt;br /&gt;
        wrapper.style.setProperty(&#039;height&#039;, wrapperHeight + &#039;px&#039;, &#039;important&#039;);&lt;br /&gt;
        wrapper.style.setProperty(&#039;max-height&#039;, wrapperHeight + &#039;px&#039;, &#039;important&#039;);&lt;br /&gt;
        wrapper.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        wrapper.style.setProperty(&#039;overflow&#039;, &#039;visible&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        liberty.style.setProperty(&#039;height&#039;, &#039;calc(100% + 14px)&#039;, &#039;important&#039;);&lt;br /&gt;
        liberty.style.setProperty(&#039;max-height&#039;, &#039;calc(100% + 14px)&#039;, &#039;important&#039;);&lt;br /&gt;
        liberty.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        liberty.style.setProperty(&#039;display&#039;, &#039;flex&#039;, &#039;important&#039;);&lt;br /&gt;
        liberty.style.setProperty(&#039;flex-direction&#039;, &#039;column&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.style.setProperty(&#039;height&#039;, &#039;100%&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;display&#039;, &#039;flex&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;flex-direction&#039;, &#039;column&#039;, &#039;important&#039;);&lt;br /&gt;
        main.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        output.style.setProperty(&#039;flex&#039;, &#039;1 1 auto&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;height&#039;, &#039;auto&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        output.style.setProperty(&#039;position&#039;, &#039;relative&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        currentGap = Math.round(bottomTop - main.getBoundingClientRect().bottom);&lt;br /&gt;
        correction = 14 + currentGap - targetGap;&lt;br /&gt;
        correction = Math.max(-20, Math.min(30, correction));&lt;br /&gt;
        liberty.style.setProperty(&#039;height&#039;, &#039;calc(100% + &#039; + correction + &#039;px)&#039;, &#039;important&#039;);&lt;br /&gt;
        liberty.style.setProperty(&#039;max-height&#039;, &#039;calc(100% + &#039; + correction + &#039;px)&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        codeBox = findSystemDocCodeBoxForShell(output);&lt;br /&gt;
        if (!codeBox) return;&lt;br /&gt;
&lt;br /&gt;
        codeBox.setAttribute(&#039;data-clbi-system-codebox&#039;, &#039;true&#039;);&lt;br /&gt;
        codeBox.style.setProperty(&#039;display&#039;, &#039;block&#039;, &#039;important&#039;);&lt;br /&gt;
        codeBox.style.setProperty(&#039;box-sizing&#039;, &#039;border-box&#039;, &#039;important&#039;);&lt;br /&gt;
        codeBox.style.setProperty(&#039;overflow&#039;, &#039;auto&#039;, &#039;important&#039;);&lt;br /&gt;
        codeBox.style.setProperty(&#039;margin&#039;, &#039;8px 0 0&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        codeTop = codeBox.getBoundingClientRect().top;&lt;br /&gt;
        codeHeight = Math.max(220, Math.round(main.getBoundingClientRect().bottom - codeTop - gap));&lt;br /&gt;
&lt;br /&gt;
        codeBox.style.setProperty(&#039;height&#039;, codeHeight + &#039;px&#039;, &#039;important&#039;);&lt;br /&gt;
        codeBox.style.setProperty(&#039;max-height&#039;, codeHeight + &#039;px&#039;, &#039;important&#039;);&lt;br /&gt;
&lt;br /&gt;
        codeBox.querySelectorAll(&#039;pre&#039;).forEach(function (pre) {&lt;br /&gt;
            pre.setAttribute(&#039;data-clbi-system-codebox-pre&#039;, &#039;true&#039;);&lt;br /&gt;
            pre.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            pre.style.setProperty(&#039;max-width&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function scheduleSystemDocViewportForShell() {&lt;br /&gt;
        window.requestAnimationFrame(function () {&lt;br /&gt;
            applySystemDocViewportForShell();&lt;br /&gt;
        });&lt;br /&gt;
        window.setTimeout(applySystemDocViewportForShell, 80);&lt;br /&gt;
        window.setTimeout(applySystemDocViewportForShell, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        unwrapSystemDocCodePaneForShell();&lt;br /&gt;
        clearSystemDocViewportForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocIndicatorForShell();&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.createElement(&#039;div&#039;);&lt;br /&gt;
        row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
        row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
        box = document.createElement(&#039;div&#039;);&lt;br /&gt;
        box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
        meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
        meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
        label = document.createElement(&#039;span&#039;);&lt;br /&gt;
        label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
        label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
        type = document.createElement(&#039;span&#039;);&lt;br /&gt;
        type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
        type.textContent = ext;&lt;br /&gt;
&lt;br /&gt;
        title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
        title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        meta.appendChild(label);&lt;br /&gt;
        meta.appendChild(type);&lt;br /&gt;
        box.appendChild(meta);&lt;br /&gt;
        box.appendChild(title);&lt;br /&gt;
        row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
        anchor = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
            anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
        } else if (main) {&lt;br /&gt;
            main.insertBefore(row, main.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        scheduleSystemDocViewportForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        removeSystemDocIndicatorForShell();&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
            clearSystemDocViewportForShell();&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            clearSystemDocViewportForShell();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;resize&#039;, function () {&lt;br /&gt;
        scheduleSystemDocViewportForShell();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell,&lt;br /&gt;
        applySystemDocViewport: applySystemDocViewportForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2450</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2450"/>
		<updated>2026-06-01T21:37:23Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
CSS/JS 시스템 문서에서는 MediaWiki 기본 제목을 숨기고,&lt;br /&gt;
문서명은 우상단 오버레이로만 표시한다.&lt;br /&gt;
이 표식은 본문 흐름을 차지하지 않는다.&lt;br /&gt;
코드/안내문은 기존 .mw-parser-output 내부에 그대로 두고,&lt;br /&gt;
024 안정 레이아웃의 내부 스크롤 구조를 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:8px !important;&lt;br /&gt;
right:8px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 16px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;width:max-content !important;max-width:520px !important;box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:7px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:0.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:22px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:0.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78) !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
word-break:normal !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
max-width:500px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page [data-clbi-system-codebox=&amp;quot;true&amp;quot;] {&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
overflow:auto !important;&lt;br /&gt;
scrollbar-gutter:stable;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page [data-clbi-system-codebox=&amp;quot;true&amp;quot;] pre {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2449</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2449"/>
		<updated>2026-06-01T21:29:12Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
function unwrapSystemDocCodePaneForShell() {&lt;br /&gt;
        var panes = document.querySelectorAll(&#039;.clbi-system-doc-codepane&#039;);&lt;br /&gt;
&lt;br /&gt;
        panes.forEach(function (pane) {&lt;br /&gt;
            var parent;&lt;br /&gt;
            if (!pane || !pane.parentNode) return;&lt;br /&gt;
            parent = pane.parentNode;&lt;br /&gt;
            while (pane.firstChild) {&lt;br /&gt;
                parent.insertBefore(pane.firstChild, pane);&lt;br /&gt;
            }&lt;br /&gt;
            parent.removeChild(pane);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        unwrapSystemDocCodePaneForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocIndicatorForShell();&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.createElement(&#039;div&#039;);&lt;br /&gt;
        row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
        row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
        box = document.createElement(&#039;div&#039;);&lt;br /&gt;
        box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
        meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
        meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
        label = document.createElement(&#039;span&#039;);&lt;br /&gt;
        label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
        label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
        type = document.createElement(&#039;span&#039;);&lt;br /&gt;
        type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
        type.textContent = ext;&lt;br /&gt;
&lt;br /&gt;
        title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
        title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        meta.appendChild(label);&lt;br /&gt;
        meta.appendChild(type);&lt;br /&gt;
        box.appendChild(meta);&lt;br /&gt;
        box.appendChild(title);&lt;br /&gt;
        row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
        anchor = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
            anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
        } else if (main) {&lt;br /&gt;
            main.insertBefore(row, main.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        removeSystemDocIndicatorForShell();&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2448</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2448"/>
		<updated>2026-06-01T21:29:04Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
CSS/JS 시스템 문서에서는 MediaWiki 기본 제목을 숨기고,&lt;br /&gt;
문서명은 우상단 오버레이로만 표시한다.&lt;br /&gt;
이 표식은 본문 흐름을 차지하지 않는다.&lt;br /&gt;
코드/안내문은 기존 .mw-parser-output 내부에 그대로 두고,&lt;br /&gt;
024 안정 레이아웃의 내부 스크롤 구조를 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:auto !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:8px !important;&lt;br /&gt;
right:8px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 16px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;width:max-content !important;max-width:520px !important;box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:7px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:0.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:22px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:0.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78) !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
word-break:normal !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
max-width:500px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2447</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2447"/>
		<updated>2026-06-01T21:24:11Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        unwrapSystemDocCodePaneForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    function unwrapSystemDocCodePaneForShell() {&lt;br /&gt;
        var pane = document.querySelector(&#039;.clbi-system-doc-codepane&#039;);&lt;br /&gt;
        var parent;&lt;br /&gt;
&lt;br /&gt;
        if (!pane || !pane.parentNode) return;&lt;br /&gt;
&lt;br /&gt;
        parent = pane.parentNode;&lt;br /&gt;
        while (pane.firstChild) {&lt;br /&gt;
            parent.insertBefore(pane.firstChild, pane);&lt;br /&gt;
        }&lt;br /&gt;
        parent.removeChild(pane);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isSystemDocCodeNodeForShell(node) {&lt;br /&gt;
        if (!node || node.nodeType !== 1) return false;&lt;br /&gt;
        if (node.id === &#039;clbi-system-doc-indicator-row&#039;) return false;&lt;br /&gt;
&lt;br /&gt;
        return node.matches(&#039;pre, .mw-highlight, .mw-code, .mw-highlight-lines, .mw-highlight-linenos&#039;) ||&lt;br /&gt;
            !!node.querySelector(&#039;pre, code, .mw-highlight, .mw-code&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function prepareSystemDocCodePaneForShell() {&lt;br /&gt;
        var output;&lt;br /&gt;
        var pane;&lt;br /&gt;
        var children;&lt;br /&gt;
        var startIndex;&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        output = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        if (!output || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        pane = output.querySelector(&#039;:scope &amp;gt; .clbi-system-doc-codepane&#039;);&lt;br /&gt;
        if (pane) return;&lt;br /&gt;
&lt;br /&gt;
        children = Array.prototype.slice.call(output.children || []);&lt;br /&gt;
        startIndex = -1;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; children.length; i += 1) {&lt;br /&gt;
            if (isSystemDocCodeNodeForShell(children[i])) {&lt;br /&gt;
                startIndex = i;&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (startIndex &amp;lt; 0) return;&lt;br /&gt;
&lt;br /&gt;
        pane = document.createElement(&#039;div&#039;);&lt;br /&gt;
        pane.className = &#039;clbi-system-doc-codepane&#039;;&lt;br /&gt;
        output.insertBefore(pane, children[startIndex]);&lt;br /&gt;
&lt;br /&gt;
        for (i = startIndex; i &amp;lt; children.length; i += 1) {&lt;br /&gt;
            if (children[i].parentNode === output &amp;amp;&amp;amp; children[i].id !== &#039;clbi-system-doc-indicator-row&#039;) {&lt;br /&gt;
                pane.appendChild(children[i]);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocIndicatorForShell();&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.createElement(&#039;div&#039;);&lt;br /&gt;
        row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
        row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
        box = document.createElement(&#039;div&#039;);&lt;br /&gt;
        box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
        meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
        meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
        label = document.createElement(&#039;span&#039;);&lt;br /&gt;
        label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
        label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
        type = document.createElement(&#039;span&#039;);&lt;br /&gt;
        type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
        type.textContent = ext;&lt;br /&gt;
&lt;br /&gt;
        title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
        title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        meta.appendChild(label);&lt;br /&gt;
        meta.appendChild(type);&lt;br /&gt;
        box.appendChild(meta);&lt;br /&gt;
        box.appendChild(title);&lt;br /&gt;
        row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
        anchor = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
            anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
        } else if (main) {&lt;br /&gt;
            main.insertBefore(row, main.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        prepareSystemDocCodePaneForShell();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        removeSystemDocIndicatorForShell();&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2446</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2446"/>
		<updated>2026-06-01T21:23:50Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
MediaWiki CSS/JS 문서는 기본 제목을 숨기고 우상단 시스템 문서 표식만 띄운다.&lt;br /&gt;
캐시 안내문은 유지한다.&lt;br /&gt;
실제 코드 본문은 JS가 .clbi-system-doc-codepane으로 묶고, 그 패널 안에서 스크롤한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; p,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; ul,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; ol,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; dl,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; .mw-parser-output-warning {&lt;br /&gt;
flex:0 0 auto !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codepane {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:8px 0 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:auto !important;&lt;br /&gt;
background:#f3f6f7 !important;&lt;br /&gt;
color:#111 !important;&lt;br /&gt;
scrollbar-gutter:stable;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codepane &amp;gt; * {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codepane pre,&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codepane code,&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codepane .mw-code,&lt;br /&gt;
body.clbi-system-doc-page .clbi-system-doc-codepane .mw-highlight {&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:10px !important;&lt;br /&gt;
right:10px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 20px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
max-width:560px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:7px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:0.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
max-width:520px !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
word-break:normal !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:24px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:0.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2445</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2445"/>
		<updated>2026-06-01T21:20:32Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100% !important;&lt;br /&gt;
overflow-x:auto !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
CSS/JS 문서에서는 MediaWiki 기본 제목만 숨기고,&lt;br /&gt;
문서명 표시는 본문 흐름에서 빠진 우상단 오버레이로 처리한다.&lt;br /&gt;
캐시 안내문은 문서 내용의 일부로 유지한다.&lt;br /&gt;
코드 본문은 남은 높이를 채우는 내부 스크롤 패널로 고정한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 캐시 안내문은 원래 문서 안내로 유지한다. */&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; p,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; ul,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; ol,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; .mw-parser-output-warning {&lt;br /&gt;
flex:0 0 auto !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 실제 코드 출력 영역. MediaWiki 버전에 따라 wrapper 구조가 다르므로 모두 받는다. */&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; .mw-highlight,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; .mw-code,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; pre,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; div:has(.mw-highlight),&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; div:has(pre) {&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
margin:8px 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
overflow:auto !important;&lt;br /&gt;
background:#f5f8fa !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; .mw-highlight:first-child,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; .mw-code:first-child,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; pre:first-child,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; div:has(.mw-highlight):first-child,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; div:has(pre):first-child {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output .mw-highlight,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output .mw-code,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output pre,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output code {&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output .mw-highlight {&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
overflow:auto !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output .mw-highlight pre,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output pre.mw-code {&lt;br /&gt;
min-height:100% !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:10px !important;&lt;br /&gt;
right:10px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 20px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
max-width:560px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:6px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
min-width:20px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
max-width:540px !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:20px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,.78) !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
word-break:normal !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2444</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2444"/>
		<updated>2026-06-01T21:17:15Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100% !important;&lt;br /&gt;
overflow-x:auto !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
CSS/JS 문서에서는 MediaWiki 기본 제목만 숨기고,&lt;br /&gt;
문서명 표시는 본문 흐름에서 빠진 우상단 오버레이로 처리한다.&lt;br /&gt;
캐시 안내문은 문서 내용의 일부로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 0 !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:auto !important;&lt;br /&gt;
scrollbar-gutter:stable;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output pre,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output code,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output .mw-code,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output .mw-highlight {&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:10px !important;&lt;br /&gt;
right:10px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 20px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
max-width:560px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:6px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
min-width:20px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
max-width:540px !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:20px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,.78) !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
word-break:normal !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2443</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2443"/>
		<updated>2026-06-01T21:13:22Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 표시 및 내부 스크롤&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* CSS/JS 시스템 문서의 안내문은 코드 스크롤 영역을 밀지 않게 숨긴다. */&lt;br /&gt;
body.clbi-system-doc-page #mw-clearyourcache,&lt;br /&gt;
body.clbi-system-doc-page .mw-clearyourcache,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; p:first-child,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output &amp;gt; ul:first-of-type {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:none !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:auto !important;&lt;br /&gt;
scrollbar-gutter:stable;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output pre,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output code,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output .mw-code,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-main .mw-parser-output .mw-highlight {&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute !important;&lt;br /&gt;
top:10px !important;&lt;br /&gt;
right:10px !important;&lt;br /&gt;
z-index:40 !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:calc(100% - 20px) !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:block !important;&lt;br /&gt;
pointer-events:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
display:block !important;&lt;br /&gt;
width:max-content !important;&lt;br /&gt;
max-width:520px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
padding:5px 8px 6px !important;&lt;br /&gt;
background:#171717 !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
justify-content:flex-end !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
gap:6px !important;&lt;br /&gt;
margin:0 0 3px 0 !important;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
letter-spacing:.08em !important;&lt;br /&gt;
text-transform:uppercase !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex !important;&lt;br /&gt;
height:14px !important;&lt;br /&gt;
min-width:20px !important;&lt;br /&gt;
padding:0 5px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
background:#0d0d0d !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block !important;&lt;br /&gt;
max-width:500px !important;&lt;br /&gt;
text-align:right !important;&lt;br /&gt;
font-size:20px !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
font-weight:900 !important;&lt;br /&gt;
letter-spacing:.01em !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,.78) !important;&lt;br /&gt;
white-space:nowrap !important;&lt;br /&gt;
word-break:normal !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
text-overflow:ellipsis !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2442</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2442"/>
		<updated>2026-06-01T21:01:26Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-B. MediaWiki CSS/JS 문서 인디케이터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
margin:0 0 8px 0;&lt;br /&gt;
padding:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
justify-content:flex-end;&lt;br /&gt;
align-items:flex-start;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
min-width:320px;&lt;br /&gt;
max-width:min(56%, 860px);&lt;br /&gt;
padding:10px 14px 12px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.012),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.38) !important;&lt;br /&gt;
background-image:linear-gradient(to bottom, rgba(255,255,255,0.020), rgba(0,0,0,0.08));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
justify-content:flex-end;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
margin:0 0 6px 0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.08em;&lt;br /&gt;
text-transform:uppercase;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
background:#0d0d0d;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block;&lt;br /&gt;
text-align:right;&lt;br /&gt;
font-size:34px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
font-weight:900;&lt;br /&gt;
letter-spacing:0.01em;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78);&lt;br /&gt;
word-break:break-word;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2441</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2441"/>
		<updated>2026-06-01T20:58:10Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-B. MediaWiki CSS/JS 문서 인디케이터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:16px;&lt;br /&gt;
right:16px;&lt;br /&gt;
z-index:30;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
justify-content:flex-end;&lt;br /&gt;
align-items:flex-start;&lt;br /&gt;
width:auto;&lt;br /&gt;
max-width:calc(100% - 32px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:780px;&lt;br /&gt;
padding:6px 10px 8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.012),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.38) !important;&lt;br /&gt;
background-image:linear-gradient(to bottom, rgba(255,255,255,0.020), rgba(0,0,0,0.08));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
justify-content:flex-end;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
margin:0 0 4px 0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.08em;&lt;br /&gt;
text-transform:uppercase;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
background:#0d0d0d;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block;&lt;br /&gt;
text-align:right;&lt;br /&gt;
font-size:27px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
font-weight:900;&lt;br /&gt;
letter-spacing:0.01em;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78);&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
word-break:normal;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
max-width:720px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2440</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2440"/>
		<updated>2026-06-01T20:53:46Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-B. MediaWiki CSS/JS 문서 인디케이터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:16px;&lt;br /&gt;
right:16px;&lt;br /&gt;
z-index:30;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
justify-content:flex-end;&lt;br /&gt;
align-items:flex-start;&lt;br /&gt;
width:auto;&lt;br /&gt;
max-width:calc(100% - 32px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
min-width:260px;&lt;br /&gt;
max-width:min(52%, 780px);&lt;br /&gt;
padding:6px 10px 8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.012),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.38) !important;&lt;br /&gt;
background-image:linear-gradient(to bottom, rgba(255,255,255,0.020), rgba(0,0,0,0.08));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
justify-content:flex-end;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
margin:0 0 4px 0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.08em;&lt;br /&gt;
text-transform:uppercase;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
background:#0d0d0d;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block;&lt;br /&gt;
text-align:right;&lt;br /&gt;
font-size:30px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
font-weight:900;&lt;br /&gt;
letter-spacing:0.01em;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78);&lt;br /&gt;
word-break:break-word;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2439</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2439"/>
		<updated>2026-06-01T20:46:43Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:AnecdoteViewer.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    var SYSTEM_TITLE_NAMESPACES = {&lt;br /&gt;
        &#039;-1&#039;: true,&lt;br /&gt;
        &#039;4&#039;: true,&lt;br /&gt;
        &#039;5&#039;: true,&lt;br /&gt;
        &#039;6&#039;: true,&lt;br /&gt;
        &#039;7&#039;: true,&lt;br /&gt;
        &#039;8&#039;: true,&lt;br /&gt;
        &#039;9&#039;: true,&lt;br /&gt;
        &#039;10&#039;: true,&lt;br /&gt;
        &#039;11&#039;: true,&lt;br /&gt;
        &#039;12&#039;: true,&lt;br /&gt;
        &#039;13&#039;: true,&lt;br /&gt;
        &#039;14&#039;: true,&lt;br /&gt;
        &#039;15&#039;: true,&lt;br /&gt;
        &#039;828&#039;: true,&lt;br /&gt;
        &#039;829&#039;: true&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    function normalizePageNameForShell(value) {&lt;br /&gt;
        return String(value || &#039;&#039;)&lt;br /&gt;
            .split(&#039;?&#039;)[0]&lt;br /&gt;
            .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
            .replace(/_/g, &#039; &#039;)&lt;br /&gt;
            .trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function readCurrentPageNameForShell() {&lt;br /&gt;
        var pageName = mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (pageName) {&lt;br /&gt;
            return normalizePageNameForShell(pageName);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return normalizePageNameForShell(window.location.pathname || &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isAnecdoteNamespaceForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var canonicalNamespace = String(mw.config.get(&#039;wgCanonicalNamespace&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 3000 ||&lt;br /&gt;
            canonicalNamespace === &#039;anecdote&#039; ||&lt;br /&gt;
            /^(anecdote|에넥도트):/i.test(pageName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isBackendOrSystemPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var action = String(mw.config.get(&#039;wgAction&#039;) || &#039;view&#039;).toLowerCase();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var lowerPageName = pageName.toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        if (action &amp;amp;&amp;amp; action !== &#039;view&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (pageName === &#039;대문&#039;) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (SYSTEM_TITLE_NAMESPACES[String(namespaceNumber)]) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;json&#039; || contentModel === &#039;sanitized-css&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\.(css|js|json)$/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/^(mediawiki|미디어위키|special|특수):/i.test(pageName)) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isMediaWikiSystemAssetPageForShell() {&lt;br /&gt;
        var namespaceNumber = Number(mw.config.get(&#039;wgNamespaceNumber&#039;));&lt;br /&gt;
        var pageName = readCurrentPageNameForShell();&lt;br /&gt;
        var contentModel = String(mw.config.get(&#039;wgPageContentModel&#039;) || &#039;&#039;).toLowerCase();&lt;br /&gt;
&lt;br /&gt;
        return namespaceNumber === 8 &amp;amp;&amp;amp;&lt;br /&gt;
            (/\.(css|js)$/i.test(pageName) || contentModel === &#039;css&#039; || contentModel === &#039;javascript&#039; || contentModel === &#039;sanitized-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeSystemDocIndicatorForShell() {&lt;br /&gt;
        var existing = document.getElementById(&#039;clbi-system-doc-indicator-row&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (document.body) {&lt;br /&gt;
            document.body.classList.remove(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (existing &amp;amp;&amp;amp; existing.parentNode) {&lt;br /&gt;
            existing.parentNode.removeChild(existing);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderSystemDocIndicatorForShell() {&lt;br /&gt;
        var pageName;&lt;br /&gt;
        var extMatch;&lt;br /&gt;
        var ext;&lt;br /&gt;
        var row;&lt;br /&gt;
        var box;&lt;br /&gt;
        var meta;&lt;br /&gt;
        var label;&lt;br /&gt;
        var type;&lt;br /&gt;
        var title;&lt;br /&gt;
        var anchor;&lt;br /&gt;
        var main;&lt;br /&gt;
&lt;br /&gt;
        removeSystemDocIndicatorForShell();&lt;br /&gt;
&lt;br /&gt;
        if (!document.body || !isMediaWikiSystemAssetPageForShell()) return;&lt;br /&gt;
&lt;br /&gt;
        pageName = readCurrentPageNameForShell();&lt;br /&gt;
        extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
        ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.classList.add(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
        row = document.createElement(&#039;div&#039;);&lt;br /&gt;
        row.id = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
        row.className = &#039;clbi-system-doc-indicator-row&#039;;&lt;br /&gt;
&lt;br /&gt;
        box = document.createElement(&#039;div&#039;);&lt;br /&gt;
        box.className = &#039;clbi-system-doc-indicator&#039;;&lt;br /&gt;
&lt;br /&gt;
        meta = document.createElement(&#039;div&#039;);&lt;br /&gt;
        meta.className = &#039;clbi-system-doc-meta&#039;;&lt;br /&gt;
&lt;br /&gt;
        label = document.createElement(&#039;span&#039;);&lt;br /&gt;
        label.className = &#039;clbi-system-doc-label&#039;;&lt;br /&gt;
        label.textContent = &#039;SYSTEM DOCUMENT&#039;;&lt;br /&gt;
&lt;br /&gt;
        type = document.createElement(&#039;span&#039;);&lt;br /&gt;
        type.className = &#039;clbi-system-doc-type&#039;;&lt;br /&gt;
        type.textContent = ext;&lt;br /&gt;
&lt;br /&gt;
        title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-system-doc-title&#039;;&lt;br /&gt;
        title.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
        meta.appendChild(label);&lt;br /&gt;
        meta.appendChild(type);&lt;br /&gt;
        box.appendChild(meta);&lt;br /&gt;
        box.appendChild(title);&lt;br /&gt;
        row.appendChild(box);&lt;br /&gt;
&lt;br /&gt;
        anchor = document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;);&lt;br /&gt;
        main = document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (anchor &amp;amp;&amp;amp; anchor.parentNode) {&lt;br /&gt;
            anchor.parentNode.insertBefore(row, anchor);&lt;br /&gt;
        } else if (main) {&lt;br /&gt;
            main.insertBefore(row, main.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var PAGE_TITLE_TARGET_SELECTORS = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var pageShellObserverStarted = false;&lt;br /&gt;
    var pageShellObserverTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function setPageTitleDomHidden(hidden) {&lt;br /&gt;
        var nodes = document.querySelectorAll(PAGE_TITLE_TARGET_SELECTORS.join(&#039;,&#039;));&lt;br /&gt;
&lt;br /&gt;
        nodes.forEach(function (node) {&lt;br /&gt;
            if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
            if (hidden) {&lt;br /&gt;
                node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
                node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
                node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
                node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClasses() {&lt;br /&gt;
        var body = document.body;&lt;br /&gt;
        var isSystemPage;&lt;br /&gt;
&lt;br /&gt;
        if (!body) return;&lt;br /&gt;
&lt;br /&gt;
        isSystemPage = isBackendOrSystemPageForShell();&lt;br /&gt;
&lt;br /&gt;
        body.classList.remove(&#039;page-title-hidden&#039;, &#039;page-title-visible&#039;, &#039;backend-system-page&#039;, &#039;anecdote-namespace-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
        removeSystemDocIndicatorForShell();&lt;br /&gt;
&lt;br /&gt;
        if (isAnecdoteNamespaceForShell()) {&lt;br /&gt;
            body.classList.add(&#039;anecdote-namespace-page&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isMediaWikiSystemAssetPageForShell()) {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;, &#039;backend-system-page&#039;, &#039;clbi-system-doc-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
            renderSystemDocIndicatorForShell();&lt;br /&gt;
        } else if (isSystemPage) {&lt;br /&gt;
            body.classList.add(&#039;page-title-visible&#039;, &#039;backend-system-page&#039;);&lt;br /&gt;
            setPageTitleDomHidden(false);&lt;br /&gt;
        } else {&lt;br /&gt;
            body.classList.add(&#039;page-title-hidden&#039;);&lt;br /&gt;
            setPageTitleDomHidden(true);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPageShellClassesDeferred() {&lt;br /&gt;
        applyPageShellClasses();&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 0);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 80);&lt;br /&gt;
        window.setTimeout(applyPageShellClasses, 250);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function startPageShellObserver() {&lt;br /&gt;
        var observer;&lt;br /&gt;
&lt;br /&gt;
        if (pageShellObserverStarted || !window.MutationObserver || !document.body) return;&lt;br /&gt;
&lt;br /&gt;
        pageShellObserverStarted = true;&lt;br /&gt;
        observer = new MutationObserver(function () {&lt;br /&gt;
            if (pageShellObserverTimer) return;&lt;br /&gt;
&lt;br /&gt;
            pageShellObserverTimer = window.setTimeout(function () {&lt;br /&gt;
                pageShellObserverTimer = null;&lt;br /&gt;
                applyPageShellClasses();&lt;br /&gt;
            }, 50);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        observer.observe(document.body, {&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
        document.addEventListener(&#039;DOMContentLoaded&#039;, function () {&lt;br /&gt;
            applyPageShellClassesDeferred();&lt;br /&gt;
            startPageShellObserver();&lt;br /&gt;
        });&lt;br /&gt;
    } else {&lt;br /&gt;
        applyPageShellClassesDeferred();&lt;br /&gt;
        startPageShellObserver();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(applyPageShellClassesDeferred);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.CLBI_PAGE_SHELL = {&lt;br /&gt;
        refresh: applyPageShellClasses,&lt;br /&gt;
        isBackendOrSystemPage: isBackendOrSystemPageForShell,&lt;br /&gt;
        isSystemAssetPage: isMediaWikiSystemAssetPageForShell,&lt;br /&gt;
        renderSystemDocIndicator: renderSystemDocIndicatorForShell,&lt;br /&gt;
        removeSystemDocIndicator: removeSystemDocIndicatorForShell&lt;br /&gt;
    };&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상·하단 네비게이션 바 ──&lt;br /&gt;
function buildClbiNavHtml(position) {&lt;br /&gt;
    var isBottom = position === &#039;bottom&#039;;&lt;br /&gt;
    var base = isBottom ? &#039;clbi-bottom&#039; : &#039;clbi-top&#039;;&lt;br /&gt;
    var shortBase = isBottom ? &#039;clbi-bnav&#039; : &#039;clbi-tnav&#039;;&lt;br /&gt;
    var wrapId = base + &#039;-nav-wrap&#039;;&lt;br /&gt;
    var navId = base + &#039;-nav&#039;;&lt;br /&gt;
    var mainId = base + &#039;-nav-main&#039;;&lt;br /&gt;
    var tabsId = base + &#039;-nav-tabs&#039;;&lt;br /&gt;
    var searchId = base + &#039;-nav-search&#039;;&lt;br /&gt;
    var inputId = isBottom ? &#039;clbi-bottom-search-input&#039; : &#039;clbi-top-search-input&#039;;&lt;br /&gt;
    var rightId = base + &#039;-nav-right&#039;;&lt;br /&gt;
    var worldId = shortBase + &#039;-worldbuilding&#039;;&lt;br /&gt;
    var infoId = shortBase + &#039;-info&#039;;&lt;br /&gt;
    var subId = isBottom ? &#039;clbi-bottom-sub-worldbuilding&#039; : &#039;clbi-sub-worldbuilding&#039;;&lt;br /&gt;
    var subInnerId = subId + &#039;-inner&#039;;&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;&#039; + wrapId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;&#039; + navId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + mainId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + tabsId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + worldId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + searchId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;&#039; + inputId + &#039;&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + rightId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;&#039; + infoId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;&#039; + subId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;&#039; + subInnerId + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $contentWrapper = $(&#039;.content-wrapper&#039;).first();&lt;br /&gt;
&lt;br /&gt;
if ($contentWrapper.length) {&lt;br /&gt;
    $(&#039;#clbi-top-nav-wrap, #clbi-bottom-nav-wrap&#039;).remove();&lt;br /&gt;
    $contentWrapper.before(buildClbiNavHtml(&#039;top&#039;));&lt;br /&gt;
    $contentWrapper.after(buildClbiNavHtml(&#039;bottom&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var root = document.documentElement;&lt;br /&gt;
    var topH = 0;&lt;br /&gt;
    var bottomH = 0;&lt;br /&gt;
&lt;br /&gt;
    if (!root) return;&lt;br /&gt;
&lt;br /&gt;
    if (top) {&lt;br /&gt;
        topH = Math.ceil(top.getBoundingClientRect().height || top.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bottom) {&lt;br /&gt;
        bottomH = Math.ceil(bottom.getBoundingClientRect().height || bottom.offsetHeight || 0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-top-nav-outer-h&#039;, topH + &#039;px&#039;);&lt;br /&gt;
    root.style.setProperty(&#039;--clbi-bottom-nav-outer-h&#039;, bottomH + &#039;px&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleClbiShellMetrics() {&lt;br /&gt;
    updateClbiShellMetrics();&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 0);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 80);&lt;br /&gt;
    window.setTimeout(updateClbiShellMetrics, 240);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function watchClbiShellMetrics() {&lt;br /&gt;
    var top = document.getElementById(&#039;clbi-top-nav-wrap&#039;);&lt;br /&gt;
    var bottom = document.getElementById(&#039;clbi-bottom-nav-wrap&#039;);&lt;br /&gt;
    var observer;&lt;br /&gt;
&lt;br /&gt;
    scheduleClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
    $(window).on(&#039;resize orientationchange&#039;, scheduleClbiShellMetrics);&lt;br /&gt;
&lt;br /&gt;
    if (window.ResizeObserver) {&lt;br /&gt;
        observer = new ResizeObserver(scheduleClbiShellMetrics);&lt;br /&gt;
        if (top) observer.observe(top);&lt;br /&gt;
        if (bottom) observer.observe(bottom);&lt;br /&gt;
        window.CLBI_SHELL_RESIZE_OBSERVER = observer;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindClbiWorldbuildingToggle(buttonSelector, menuSelector) {&lt;br /&gt;
    $(buttonSelector).on(&#039;click&#039;, function() {&lt;br /&gt;
        var $menu = $(menuSelector);&lt;br /&gt;
        var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
        $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
        scheduleClbiShellMetrics();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-tnav-worldbuilding&#039;, &#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
bindClbiWorldbuildingToggle(&#039;#clbi-bnav-worldbuilding&#039;, &#039;#clbi-bottom-sub-worldbuilding&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input, #clbi-bottom-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
watchClbiShellMetrics();&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function setNativePageTitleHiddenHard(hidden) {&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.liberty-content-header&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title&#039;,&lt;br /&gt;
        &#039;.liberty-content-header .title h1&#039;,&lt;br /&gt;
        &#039;.liberty-content-header h1&#039;,&lt;br /&gt;
        &#039;#firstHeading&#039;,&lt;br /&gt;
        &#039;.firstHeading&#039;,&lt;br /&gt;
        &#039;.mw-first-heading&#039;,&lt;br /&gt;
        &#039;.page-heading&#039;,&lt;br /&gt;
        &#039;.page-header&#039;,&lt;br /&gt;
        &#039;.mw-page-title-main&#039;,&lt;br /&gt;
        &#039;.mw-page-title-namespace&#039;,&lt;br /&gt;
        &#039;.mw-page-title-separator&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    document.querySelectorAll(selectors.join(&#039;,&#039;)).forEach(function(node) {&lt;br /&gt;
        if (!node || !node.style) return;&lt;br /&gt;
&lt;br /&gt;
        if (hidden) {&lt;br /&gt;
            node.setAttribute(&#039;data-clbi-title-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;display&#039;, &#039;none&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;visibility&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;min-height&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;margin&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;padding&#039;, &#039;0&#039;, &#039;important&#039;);&lt;br /&gt;
            node.style.setProperty(&#039;overflow&#039;, &#039;hidden&#039;, &#039;important&#039;);&lt;br /&gt;
        } else if (node.getAttribute(&#039;data-clbi-title-hidden&#039;) === &#039;true&#039;) {&lt;br /&gt;
            node.removeAttribute(&#039;data-clbi-title-hidden&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;display&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;visibility&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;min-height&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;margin&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;padding&#039;);&lt;br /&gt;
            node.style.removeProperty(&#039;overflow&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyDefaultPageTitleVisibility() {&lt;br /&gt;
    var hideTitle = true;&lt;br /&gt;
    var isSystemAssetPage = false;&lt;br /&gt;
&lt;br /&gt;
    if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isSystemAssetPage === &#039;function&#039;) {&lt;br /&gt;
        isSystemAssetPage = window.CLBI_PAGE_SHELL.isSystemAssetPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage) {&lt;br /&gt;
        hideTitle = true;&lt;br /&gt;
    } else if (window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.isBackendOrSystemPage === &#039;function&#039;) {&lt;br /&gt;
        hideTitle = !window.CLBI_PAGE_SHELL.isBackendOrSystemPage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;)&lt;br /&gt;
        .toggleClass(&#039;page-title-hidden&#039;, hideTitle)&lt;br /&gt;
        .toggleClass(&#039;page-title-visible&#039;, !hideTitle)&lt;br /&gt;
        .toggleClass(&#039;clbi-system-doc-page&#039;, isSystemAssetPage);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.renderSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.renderSystemDocIndicator();&lt;br /&gt;
    } else if (!isSystemAssetPage &amp;amp;&amp;amp; window.CLBI_PAGE_SHELL &amp;amp;&amp;amp; typeof window.CLBI_PAGE_SHELL.removeSystemDocIndicator === &#039;function&#039;) {&lt;br /&gt;
        window.CLBI_PAGE_SHELL.removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTitle) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;#firstHeading, .firstHeading, .mw-first-heading, .page-heading, .page-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;clbi-main-page&#039;, isMainPage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        setNativePageTitleHiddenHard(true);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
    applyDefaultPageTitleVisibility();&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2438</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2438"/>
		<updated>2026-06-01T20:46:27Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
--layout-gap-double:16px;&lt;br /&gt;
--clbi-top-nav-outer-h:47px;&lt;br /&gt;
--clbi-bottom-nav-outer-h:47px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
overflow-y:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
height:100vh !important;&lt;br /&gt;
overflow-x:visible !important;&lt;br /&gt;
overflow-y:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
#clbi-bottom-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-bottom-nav-wrap {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 var(--layout-gap) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:stretch !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
max-height:calc(100vh - var(--clbi-top-nav-outer-h, 47px) - var(--clbi-bottom-nav-outer-h, 47px) - var(--layout-gap-double, 16px)) !important;&lt;br /&gt;
overflow:visible !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
/*&lt;br /&gt;
Liberty/Bootstrap의 중앙 content 래퍼는 grid 행 안에서 height:100%를 잡아도&lt;br /&gt;
실제 wrapper 높이보다 14px 짧게 계산된다. 이 14px은 화면에 보이는&lt;br /&gt;
본문 컨테이너 하단 ↔ 하단 네비 사이의 추가 빈공간으로 나타난다.&lt;br /&gt;
좌우 사이드바나 외부 셸을 건드리지 않고 중앙 래퍼만 보정한다.&lt;br /&gt;
*/&lt;br /&gt;
height:calc(100% + 14px) !important;&lt;br /&gt;
max-height:calc(100% + 14px) !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
본문 컨테이너는 바깥 장비 프레임과 내부 우물로 분리한다.&lt;br /&gt;
- .liberty-content는 투명 래퍼로 유지한다.&lt;br /&gt;
- .liberty-content-main은 외곽 프레임이다.&lt;br /&gt;
- .mw-parser-output은 실제 본문이 놓이는 내부 우물이다.&lt;br /&gt;
- 외곽과 본문 사이의 기본 간격은 8px이다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content-main {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid #050505 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
flex-direction:column !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
position:relative !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
flex:1 1 auto !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:8px !important;&lt;br /&gt;
background:#080808 !important;&lt;br /&gt;
border:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555 !important;&lt;br /&gt;
overflow-y:auto !important;&lt;br /&gt;
overflow-x:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output,&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
scrollbar-width:thin;&lt;br /&gt;
scrollbar-color:#333333 #080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 제목이 유지되는 관리/시스템 문서는 제목 영역과 본문 우물 사이에 8px 간격을 둔다. */&lt;br /&gt;
body.page-title-visible .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.backend-system-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:8px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* title을 숨긴 일반 문서는 내부 우물이 바로 본문 시작점이 된다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 일반 문서에서는 기본 제목 영역을 숨긴다.&lt;br /&gt;
   CSS/JS/JSON, MediaWiki, 특수문서, 틀, 파일, 분류 같은 시스템 문서는&lt;br /&gt;
   Common.js가 body.backend-system-page를 부여하므로 제목을 유지한다. */&lt;br /&gt;
body.page-title-hidden .liberty-content-header,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title h1 {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-title-hidden .mw-page-title-main,&lt;br /&gt;
body.page-title-hidden .mw-page-title-main::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace,&lt;br /&gt;
body.page-title-hidden .mw-page-title-namespace::after,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator,&lt;br /&gt;
body.page-title-hidden .mw-page-title-separator::after,&lt;br /&gt;
body.page-title-hidden .liberty-content-header .title,&lt;br /&gt;
body.page-title-hidden .liberty-content-header h1,&lt;br /&gt;
body.page-title-hidden #firstHeading,&lt;br /&gt;
body.page-title-hidden .firstHeading,&lt;br /&gt;
body.page-title-hidden .mw-first-heading,&lt;br /&gt;
body.page-title-hidden .page-heading,&lt;br /&gt;
body.page-title-hidden .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Anecdote 네임스페이스도 작품/회차 일반 문서 계열로 본다.&lt;br /&gt;
   감상 모드 여부와 관계없이 MediaWiki 기본 제목은 숨기고,&lt;br /&gt;
   뷰어 내부 제목과 작품 허브 내부 제목만 사용한다. */&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title,&lt;br /&gt;
body.anecdote-namespace-page .liberty-content-header .title h1,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-main::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-namespace::after,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator,&lt;br /&gt;
body.anecdote-namespace-page .mw-page-title-separator::after,&lt;br /&gt;
body.anecdote-namespace-page #firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .firstHeading,&lt;br /&gt;
body.anecdote-namespace-page .mw-first-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-heading,&lt;br /&gt;
body.anecdote-namespace-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* action-view fallback: 일반 열람 문서는 JS 재적용 타이밍과 무관하게 기본 제목을 숨긴다.&lt;br /&gt;
   backend/system 문서는 Common.js가 body.backend-system-page를 붙여 제목을 유지한다. */&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header .title h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header h1,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-main::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-page-title-separator::after,&lt;br /&gt;
body.action-view:not(.backend-system-page) #firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .firstHeading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .mw-first-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-heading,&lt;br /&gt;
body.action-view:not(.backend-system-page) .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view:not(.backend-system-page) .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* 대문 title hard fallback&lt;br /&gt;
   Theme.css가 뒤에서 .mw-page-title-main을 다시 보이게 하더라도&lt;br /&gt;
   대문 열람 화면에서는 MediaWiki 기본 제목을 강제로 숨긴다. */&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.page-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.page-대문 #firstHeading,&lt;br /&gt;
body.action-view.page-대문 .firstHeading,&lt;br /&gt;
body.action-view.page-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.page-대문 .page-heading,&lt;br /&gt;
body.action-view.page-대문 .page-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header .title h1,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header h1,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-main::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-namespace::after,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-page-title-separator::after,&lt;br /&gt;
body.action-view.rootpage-대문 #firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .firstHeading,&lt;br /&gt;
body.action-view.rootpage-대문 .mw-first-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-heading,&lt;br /&gt;
body.action-view.rootpage-대문 .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.action-view.page-대문 .liberty-content-header + .mw-parser-output,&lt;br /&gt;
body.action-view.rootpage-대문 .liberty-content-header + .mw-parser-output {&lt;br /&gt;
margin-top:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 문서 조작 버튼은 DevTools의 DOCUMENT TOOLS로 이동한다. */&lt;br /&gt;
.liberty-content-header .content-tools,&lt;br /&gt;
.content-tools {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-B. MediaWiki CSS/JS 문서 인디케이터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
margin:0 0 8px 0;&lt;br /&gt;
padding:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
justify-content:flex-end;&lt;br /&gt;
align-items:flex-start;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
min-width:320px;&lt;br /&gt;
max-width:min(56%, 860px);&lt;br /&gt;
padding:10px 14px 12px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.012),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.38) !important;&lt;br /&gt;
background-image:linear-gradient(to bottom, rgba(255,255,255,0.020), rgba(0,0,0,0.08));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
justify-content:flex-end;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
margin:0 0 6px 0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.08em;&lt;br /&gt;
text-transform:uppercase;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
background:#0d0d0d;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block;&lt;br /&gt;
text-align:right;&lt;br /&gt;
font-size:34px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
font-weight:900;&lt;br /&gt;
letter-spacing:0.01em;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78);&lt;br /&gt;
word-break:break-word;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header .title h1,&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header h1,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator::after,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-heading,&lt;br /&gt;
body.clbi-system-doc-page .page-header {&lt;br /&gt;
display:none !important;&lt;br /&gt;
visibility:hidden !important;&lt;br /&gt;
height:0 !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
max-height:100%;&lt;br /&gt;
overflow-y:auto;&lt;br /&gt;
overflow-x:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav,&lt;br /&gt;
#clbi-bottom-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main,&lt;br /&gt;
#clbi-bottom-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo,&lt;br /&gt;
#clbi-bottom-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img,&lt;br /&gt;
#clbi-bottom-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs,&lt;br /&gt;
#clbi-bottom-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search,&lt;br /&gt;
#clbi-bottom-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input,&lt;br /&gt;
#clbi-bottom-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus,&lt;br /&gt;
#clbi-bottom-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right,&lt;br /&gt;
#clbi-bottom-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18-1. 대문 전용 상·하단 네비 최소화&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
대문에서는 본문 내부에 카테고리 네비와 대문 전용 조작 구조가 이미 있으므로,&lt;br /&gt;
상단·하단 네비바는 검색 슬롯만 남긴다.&lt;br /&gt;
다른 문서에서는 기존 버튼 구성을 그대로 유지한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-top-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-tabs,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-tabs,&lt;br /&gt;
body.clbi-main-page #clbi-top-nav-right,&lt;br /&gt;
body.page-대문 #clbi-top-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-nav-right,&lt;br /&gt;
body.page-대문 #clbi-bottom-nav-right,&lt;br /&gt;
body.clbi-main-page #clbi-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-sub-worldbuilding,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-sub-worldbuilding,&lt;br /&gt;
body.page-대문 #clbi-bottom-sub-worldbuilding {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input,&lt;br /&gt;
body.page-대문 #clbi-top-search-input,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input {&lt;br /&gt;
width:288px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-main-page #clbi-top-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-top-search-input:focus,&lt;br /&gt;
body.clbi-main-page #clbi-bottom-search-input:focus,&lt;br /&gt;
body.page-대문 #clbi-bottom-search-input:focus {&lt;br /&gt;
width:384px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-bottom-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-bottom-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2437</id>
		<title>미디어위키:Common.js</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Common.js&amp;diff=2437"/>
		<updated>2026-06-01T20:36:18Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&#039;https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:DevTools.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
mw.loader.load(&#039;/index.php?title=MediaWiki:CategoryNav.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;);&lt;br /&gt;
&lt;br /&gt;
function loadLangScript(done) {&lt;br /&gt;
    $.getScript(&#039;/index.php?title=미디어위키:Lang.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039;)&lt;br /&gt;
        .done(function() {&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        })&lt;br /&gt;
        .fail(function(a, b, c) {&lt;br /&gt;
            console.error(&#039;Lang.js load failed:&#039;, b, c);&lt;br /&gt;
            if (typeof done === &#039;function&#039;) done();&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function initHalftoneBackground() {&lt;br /&gt;
    try {&lt;br /&gt;
        initWebGLHalftoneBackground();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;WebGL halftone background failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initWebGLHalftoneBackground() {&lt;br /&gt;
    var canvasId = &#039;site-halftone-bg&#039;;&lt;br /&gt;
    var existing = document.getElementById(canvasId);&lt;br /&gt;
    var canvas = existing || document.createElement(&#039;canvas&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!existing) {&lt;br /&gt;
        canvas.id = canvasId;&lt;br /&gt;
        canvas.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
        document.body.insertBefore(canvas, document.body.firstChild || null);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    canvas.style.position = &#039;fixed&#039;;&lt;br /&gt;
    canvas.style.inset = &#039;0&#039;;&lt;br /&gt;
    canvas.style.width = &#039;100vw&#039;;&lt;br /&gt;
    canvas.style.height = &#039;100vh&#039;;&lt;br /&gt;
    canvas.style.pointerEvents = &#039;none&#039;;&lt;br /&gt;
    canvas.style.background = &#039;#000000&#039;;&lt;br /&gt;
&lt;br /&gt;
    var gl = canvas.getContext(&#039;webgl&#039;, {&lt;br /&gt;
        alpha: false,&lt;br /&gt;
        antialias: false,&lt;br /&gt;
        depth: false,&lt;br /&gt;
        stencil: false,&lt;br /&gt;
        preserveDrawingBuffer: false,&lt;br /&gt;
        powerPreference: &#039;high-performance&#039;&lt;br /&gt;
    }) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!gl) {&lt;br /&gt;
        console.warn(&#039;WebGL background unavailable.&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexSrc = [&lt;br /&gt;
        &#039;attribute vec2 a_position;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_position, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var fragmentSrc = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_resolution;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;const float TAU = 6.28318530718;&#039;,&lt;br /&gt;
        &#039;float gaussian(float v, float r) {&#039;,&lt;br /&gt;
        &#039;  return exp(-((v * v) / max(0.0001, r * r)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float hash(vec2 p) {&#039;,&lt;br /&gt;
        &#039;  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;float bucketAlpha(float a) {&#039;,&lt;br /&gt;
        &#039;  float i = floor(a * 9.0);&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 1.0) return 0.040;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 2.0) return 0.080;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 3.0) return 0.135;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 4.0) return 0.210;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 5.0) return 0.310;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 6.0) return 0.430;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 7.0) return 0.580;&#039;,&lt;br /&gt;
        &#039;  if (i &amp;lt; 8.0) return 0.760;&#039;,&lt;br /&gt;
        &#039;  return 0.920;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 frag = gl_FragCoord.xy;&#039;,&lt;br /&gt;
        &#039;  float spacing = 5.0;&#039;,&lt;br /&gt;
        &#039;  float dotSize = 1.08;&#039;,&lt;br /&gt;
        &#039;  vec2 grid = floor(frag / spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 inCell = mod(frag, spacing);&#039;,&lt;br /&gt;
        &#039;  vec2 dotOrigin = vec2(1.0, 1.0);&#039;,&lt;br /&gt;
        &#039;  vec2 dotCenter = dotOrigin + vec2(dotSize * 0.5);&#039;,&lt;br /&gt;
        &#039;  vec2 local = abs(inCell - dotCenter);&#039;,&lt;br /&gt;
        &#039;  float noise = hash(grid);&#039;,&lt;br /&gt;
        &#039;  float size = dotSize + noise * 0.18;&#039;,&lt;br /&gt;
        &#039;  float dotMask = 1.0 - smoothstep(size * 0.5, size * 0.5 + 0.22, max(local.x, local.y));&#039;,&lt;br /&gt;
        &#039;  vec2 uv = frag / u_resolution;&#039;,&lt;br /&gt;
        &#039;  float centerLine = 0.50 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 1.32 + 0.08) * TAU) * 0.070 +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 3.18 + 0.34) * TAU) * 0.030;&#039;,&lt;br /&gt;
        &#039;  float u = uv.x - centerLine;&#039;,&lt;br /&gt;
        &#039;  float absU = abs(u);&#039;,&lt;br /&gt;
        &#039;  float sideLift = smoothstep(0.065, 0.44, absU);&#039;,&lt;br /&gt;
        &#039;  float valley = gaussian(u, 0.150);&#039;,&lt;br /&gt;
        &#039;  float t = u_time;&#039;,&lt;br /&gt;
        &#039;  float leftRibbonCenter = -0.28 + sin((uv.y * 3.20 + 0.12) * TAU) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float rightRibbonCenter = 0.27 + sin((uv.y * 2.85 + 0.56) * TAU) * 0.055;&#039;,&lt;br /&gt;
        &#039;  float leftRibbon = gaussian(u - leftRibbonCenter, 0.105);&#039;,&lt;br /&gt;
        &#039;  float rightRibbon = gaussian(u - rightRibbonCenter, 0.110);&#039;,&lt;br /&gt;
        &#039;  float foldedU = u +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 4.40 + 0.22) * TAU) * 0.050 * (0.3 + sideLift) +&#039;,&lt;br /&gt;
        &#039;    sin((uv.y * 7.20 + uv.x * 1.10) * TAU) * 0.022;&#039;,&lt;br /&gt;
        &#039;  float verticalFold = pow(0.5 + 0.5 * cos(((foldedU * 3.05) + (sin(uv.y * TAU * 2.35) * 0.18)) * TAU), 2.5);&#039;,&lt;br /&gt;
        &#039;  float diagonalFold = pow(0.5 + 0.5 * cos(((foldedU * 1.80) - (uv.y * 1.12) + 0.18) * TAU), 2.1);&#039;,&lt;br /&gt;
        &#039;  float waist = gaussian(uv.y - 0.50, 0.25) * gaussian(absU - 0.20, 0.19);&#039;,&lt;br /&gt;
        &#039;  float grain = (noise - 0.5) * 0.050;&#039;,&lt;br /&gt;
        &#039;  float staticField =&#039;,&lt;br /&gt;
        &#039;    0.055 +&#039;,&lt;br /&gt;
        &#039;    sideLift * 0.210 +&#039;,&lt;br /&gt;
        &#039;    (leftRibbon + rightRibbon) * 0.145 +&#039;,&lt;br /&gt;
        &#039;    verticalFold * (0.055 + sideLift * 0.115) +&#039;,&lt;br /&gt;
        &#039;    diagonalFold * 0.045 +&#039;,&lt;br /&gt;
        &#039;    waist * 0.060 -&#039;,&lt;br /&gt;
        &#039;    valley * 0.150 +&#039;,&lt;br /&gt;
        &#039;    grain;&#039;,&lt;br /&gt;
        &#039;  float alpha = staticField;&#039;,&lt;br /&gt;
        &#039;  alpha += 0.115 * (leftRibbon + rightRibbon) * sin(t * 0.00030 + ((uv.y * 1.9) + sideLift * 0.4) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.095 * verticalFold * (0.4 + sideLift) * sin(t * 0.00041 + ((uv.y * 2.7) + foldedU * 0.65) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.070 * waist * sin(t * 0.00053 + ((uv.y * 3.1) - absU * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.060 * (1.0 - valley) * diagonalFold * sin(t * 0.00067 + ((uv.y * 1.4) + uv.x * 0.6) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha += 0.038 * (0.35 + sideLift) * (0.35 + noise) * sin(t * 0.00079 + ((uv.y * 4.6) + noise * 0.8) * TAU);&#039;,&lt;br /&gt;
        &#039;  alpha = bucketAlpha(clamp(alpha, 0.025, 0.96));&#039;,&lt;br /&gt;
        &#039;  float value = alpha * dotMask;&#039;,&lt;br /&gt;
        &#039;  gl_FragColor = vec4(vec3(0.8862745 * value), 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function compileShader(type, source) {&lt;br /&gt;
        var shader = gl.createShader(type);&lt;br /&gt;
        gl.shaderSource(shader, source);&lt;br /&gt;
        gl.compileShader(shader);&lt;br /&gt;
&lt;br /&gt;
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {&lt;br /&gt;
            console.error(&#039;WebGL shader compile error:&#039;, gl.getShaderInfoLog(shader));&lt;br /&gt;
            gl.deleteShader(shader);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return shader;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var vertexShader = compileShader(gl.VERTEX_SHADER, vertexSrc);&lt;br /&gt;
    var fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentSrc);&lt;br /&gt;
&lt;br /&gt;
    if (!vertexShader || !fragmentShader) return;&lt;br /&gt;
&lt;br /&gt;
    var program = gl.createProgram();&lt;br /&gt;
    gl.attachShader(program, vertexShader);&lt;br /&gt;
    gl.attachShader(program, fragmentShader);&lt;br /&gt;
    gl.linkProgram(program);&lt;br /&gt;
&lt;br /&gt;
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {&lt;br /&gt;
        console.error(&#039;WebGL program link error:&#039;, gl.getProgramInfoLog(program));&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var positionLoc = gl.getAttribLocation(program, &#039;a_position&#039;);&lt;br /&gt;
    var resolutionLoc = gl.getUniformLocation(program, &#039;u_resolution&#039;);&lt;br /&gt;
    var timeLoc = gl.getUniformLocation(program, &#039;u_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    var buffer = gl.createBuffer();&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([&lt;br /&gt;
        -1, -1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
        -1,  1,&lt;br /&gt;
         1, -1,&lt;br /&gt;
         1,  1&lt;br /&gt;
    ]), gl.STATIC_DRAW);&lt;br /&gt;
&lt;br /&gt;
    gl.useProgram(program);&lt;br /&gt;
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);&lt;br /&gt;
    gl.enableVertexAttribArray(positionLoc);&lt;br /&gt;
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    function resize() {&lt;br /&gt;
        var dpr = Math.min(window.devicePixelRatio || 1, 1.5);&lt;br /&gt;
        var cssW = Math.max(1, window.innerWidth || document.documentElement.clientWidth || 1);&lt;br /&gt;
        var cssH = Math.max(1, window.innerHeight || document.documentElement.clientHeight || 1);&lt;br /&gt;
        var w = Math.max(1, Math.floor(cssW * dpr));&lt;br /&gt;
        var h = Math.max(1, Math.floor(cssH * dpr));&lt;br /&gt;
&lt;br /&gt;
        if (canvas.width !== w || canvas.height !== h) {&lt;br /&gt;
            canvas.width = w;&lt;br /&gt;
            canvas.height = h;&lt;br /&gt;
            canvas.style.width = cssW + &#039;px&#039;;&lt;br /&gt;
            canvas.style.height = cssH + &#039;px&#039;;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var prefersReducedMotion = false;&lt;br /&gt;
    try {&lt;br /&gt;
        prefersReducedMotion = window.matchMedia &amp;amp;&amp;amp; window.matchMedia(&#039;(prefers-reduced-motion: reduce)&#039;).matches;&lt;br /&gt;
    } catch (err) {}&lt;br /&gt;
&lt;br /&gt;
    var lastFrame = 0;&lt;br /&gt;
    var frameInterval = prefersReducedMotion ? 1000 : 66;&lt;br /&gt;
    var startTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function render(now) {&lt;br /&gt;
        requestAnimationFrame(render);&lt;br /&gt;
        if (document.hidden) return;&lt;br /&gt;
        if (now - lastFrame &amp;lt; frameInterval) return;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        resize();&lt;br /&gt;
&lt;br /&gt;
        gl.clearColor(0, 0, 0, 1);&lt;br /&gt;
        gl.clear(gl.COLOR_BUFFER_BIT);&lt;br /&gt;
        gl.uniform2f(resolutionLoc, canvas.width, canvas.height);&lt;br /&gt;
        gl.uniform1f(timeLoc, now - startTime);&lt;br /&gt;
        gl.drawArrays(gl.TRIANGLES, 0, 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resize();&lt;br /&gt;
    requestAnimationFrame(render);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var CLBI_SVG_BELL = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_BELL_DOT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-bell-dot&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10.268 21a2 2 0 0 0 3.464 0&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M11.68 2.009A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673c-.824-.85-1.678-1.731-2.21-3.348&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;18&amp;quot; cy=&amp;quot;5&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LIST = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-list&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 5h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 12h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3 19h.01&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 5h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 12h13&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M8 19h13&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_LANGUAGES = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-languages&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;m5 8 6 6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m4 14 6-6 2-3&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M2 5h12&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 2h1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;m22 22-5-10-5 10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 18h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_POWER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-power&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 2v10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.4 6.6a9 9 0 1 1-12.77.04&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SETTINGS = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-settings&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;3&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_TEXT = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-text&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 8h8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 12h10&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 16h6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_SCAN_EYE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-scan-eye&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M3 7V5a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M17 3h2a2 2 0 0 1 2 2v2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M21 17v2a2 2 0 0 1-2 2h-2&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M7 21H5a2 2 0 0 1-2-2v-2&amp;quot;/&amp;gt;&amp;lt;circle cx=&amp;quot;12&amp;quot; cy=&amp;quot;12&amp;quot; r=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18.944 12.33a1 1 0 0 0 0-.66 7.5 7.5 0 0 0-13.888 0 1 1 0 0 0 0 .66 7.5 7.5 0 0 0 13.888 0&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_NEWSPAPER = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-newspaper&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M15 18h-5&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 14h-8&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2&amp;quot;/&amp;gt;&amp;lt;rect width=&amp;quot;8&amp;quot; height=&amp;quot;4&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;6&amp;quot; rx=&amp;quot;1&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_TROPHY = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-trophy&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M18 9h1.5a1 1 0 0 0 0-5H18&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M4 22h16&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M6 9H4.5a1 1 0 0 1 0-5H6&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
var CLBI_SVG_PACKAGE = &#039;&amp;lt;svg class=&amp;quot;profile-svg profile-svg-package&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; viewBox=&amp;quot;0 0 24 24&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;currentColor&amp;quot; stroke-width=&amp;quot;2.75&amp;quot; stroke-linecap=&amp;quot;round&amp;quot; stroke-linejoin=&amp;quot;round&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;path d=&amp;quot;M12 3v6&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z&amp;quot;/&amp;gt;&amp;lt;path d=&amp;quot;M3.054 9.013h17.893&amp;quot;/&amp;gt;&amp;lt;/svg&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
var PROFILE_RENDER_TOKEN = 0;&lt;br /&gt;
&lt;br /&gt;
function invalidateProfileRender() {&lt;br /&gt;
    PROFILE_RENDER_TOKEN++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    initHalftoneBackground();&lt;br /&gt;
&lt;br /&gt;
// ── 상단 네비게이션 바 ──&lt;br /&gt;
var navHtml =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-top-nav-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-top-nav&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;clbi-top-nav-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-top-nav-tabs&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/대문&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-main-menu-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;메인 메뉴&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
&#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
&#039;&amp;lt;a class=&amp;quot;clbi-top-nav-item&amp;quot; href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-project-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;프로젝트&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
&#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
&#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;clbi-tnav-worldbuilding&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;img class=&amp;quot;clbi-tnav-icon&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Ic-worldbuilding-001.png&amp;quot; alt=&amp;quot;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;세계관&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;span class=&amp;quot;clbi-tnav-arrow&amp;quot;&amp;gt;▾&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
&#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-top-nav-search&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;clbi-top-search-input&amp;quot; placeholder=&amp;quot;검색...&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-top-nav-right&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-top-nav-item&amp;quot; id=&amp;quot;clbi-tnav-info&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;clbi-tnav-label&amp;quot;&amp;gt;ℹ&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
&#039;&amp;lt;div id=&amp;quot;clbi-sub-worldbuilding&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-sub-worldbuilding-inner&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-tnav-sub-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/역사적_사건&amp;quot;&amp;gt;역사적 사건&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
&#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/설정&amp;quot;&amp;gt;설정&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
&#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/국가_및_조합&amp;quot;&amp;gt;국가 및 조합&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
&#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/기업_및_공동체&amp;quot;&amp;gt;기업 및 공동체&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
&#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/군_정치집단&amp;quot;&amp;gt;군, 정치집단&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
&#039;&amp;lt;a class=&amp;quot;clbi-tnav-sub-item&amp;quot; href=&amp;quot;/index.php/인물&amp;quot;&amp;gt;인물&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
$(&#039;.content-wrapper&#039;).before(navHtml);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-tnav-worldbuilding&#039;).on(&#039;click&#039;, function() {&lt;br /&gt;
    var $menu = $(&#039;#clbi-sub-worldbuilding&#039;);&lt;br /&gt;
    var $btn = $(this);&lt;br /&gt;
&lt;br /&gt;
    $menu.toggleClass(&#039;worldbuilding-open&#039;);&lt;br /&gt;
    $btn.toggleClass(&#039;clbi-tnav-active&#039;, $menu.hasClass(&#039;worldbuilding-open&#039;));&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-top-search-input&#039;).on(&#039;keydown&#039;, function(e) {&lt;br /&gt;
    if (e.key === &#039;Enter&#039;) {&lt;br /&gt;
        var q = $(this).val().trim();&lt;br /&gt;
        if (q) window.location.href = &#039;/index.php?search=&#039; + encodeURIComponent(q);&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 페이지 전환 사운드&lt;br /&gt;
var transitionSound = new Audio(&#039;/index.php?title=특수:Redirect/file/Sfx-ui-001.mp3&#039;);&lt;br /&gt;
&lt;br /&gt;
(function() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
    transitionSound.volume = sfxOn ? master * sfx : 0;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
function playStaticSound() {&lt;br /&gt;
    var master = parseFloat(localStorage.getItem(&#039;clbi-audio-master&#039;) || 80) / 100;&lt;br /&gt;
    var sfx = parseFloat(localStorage.getItem(&#039;clbi-audio-sfx&#039;) || 60) / 100;&lt;br /&gt;
    var sfxOn = localStorage.getItem(&#039;clbi-audio-sfxOn&#039;) !== &#039;false&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (!sfxOn) return;&lt;br /&gt;
&lt;br /&gt;
    transitionSound.volume = master * sfx;&lt;br /&gt;
    transitionSound.currentTime = 0;&lt;br /&gt;
    transitionSound.play();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 현재 언어 감지&lt;br /&gt;
function getCurrentLang() {&lt;br /&gt;
    var langData = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    return langData ? (langData.getAttribute(&#039;data-lang&#039;) || &#039;ko&#039;) : &#039;ko&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizePageName(value) {&lt;br /&gt;
    return String(value || &#039;&#039;)&lt;br /&gt;
        .split(&#039;?&#039;)[0]&lt;br /&gt;
        .replace(/^\/index\.php\//, &#039;&#039;)&lt;br /&gt;
        .replace(/_/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildWikiPath(title) {&lt;br /&gt;
    return &#039;/index.php/&#039; + encodeURI(String(title || &#039;&#039;).replace(/ /g, &#039;_&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLangShortCode(lang) {&lt;br /&gt;
    var map = { ko: &#039;KR&#039;, en: &#039;EN&#039;, zh: &#039;ZH&#039;, ja: &#039;JA&#039;, ru: &#039;RU&#039;, es: &#039;ES&#039; };&lt;br /&gt;
    return map[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLanguageTargetTitle(lang) {&lt;br /&gt;
    var data = document.getElementById(&#039;clbi-lang-data&#039;);&lt;br /&gt;
    if (!data || !lang) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var keys = [&lt;br /&gt;
        &#039;data-&#039; + lang,&lt;br /&gt;
        &#039;data-page-&#039; + lang,&lt;br /&gt;
        &#039;data-title-&#039; + lang,&lt;br /&gt;
        &#039;data-target-&#039; + lang,&lt;br /&gt;
        &#039;data-lang-&#039; + lang&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; keys.length; i++) {&lt;br /&gt;
        var value = data.getAttribute(keys[i]);&lt;br /&gt;
        if (value) return value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var SIDEBAR_LANG_SVG_NS = &#039;http://www.w3.org/2000/svg&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_TITLE = &#039;MediaWiki:LanguageStatus.json&#039;;&lt;br /&gt;
var SIDEBAR_LANGUAGE_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;English&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;Русский&#039;,&lt;br /&gt;
    es: &#039;Español&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_DIAL_LABELS = {&lt;br /&gt;
    ko: &#039;한국어&#039;,&lt;br /&gt;
    en: &#039;ENG&#039;,&lt;br /&gt;
    zh: &#039;中文&#039;,&lt;br /&gt;
    ja: &#039;日本語&#039;,&lt;br /&gt;
    ru: &#039;РУС&#039;,&lt;br /&gt;
    es: &#039;ESP&#039;&lt;br /&gt;
};&lt;br /&gt;
var SIDEBAR_LANGUAGE_STATUS_VALUES = {&lt;br /&gt;
    available: true,&lt;br /&gt;
    wip: true,&lt;br /&gt;
    unavailable: true&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageStatusRegistry = {};&lt;br /&gt;
var sidebarLanguageStatusLoaded = false;&lt;br /&gt;
var sidebarLanguageStatusLoading = false;&lt;br /&gt;
var sidebarLanguageStatusCallbacks = [];&lt;br /&gt;
&lt;br /&gt;
var sidebarLanguageState = {&lt;br /&gt;
    order: [&#039;ko&#039;, &#039;en&#039;, &#039;zh&#039;, &#039;ja&#039;, &#039;ru&#039;, &#039;es&#039;],&lt;br /&gt;
    currentLang: &#039;ko&#039;,&lt;br /&gt;
    baseIndex: 0,&lt;br /&gt;
    selectedIndex: 0,&lt;br /&gt;
    rotation: 0,&lt;br /&gt;
    dragging: false,&lt;br /&gt;
    dragMoved: false,&lt;br /&gt;
    dragStartX: 0,&lt;br /&gt;
    dragStartY: 0,&lt;br /&gt;
    dragStartRotation: 0,&lt;br /&gt;
    dragAxis: null,&lt;br /&gt;
    pointerCaptured: false,&lt;br /&gt;
    lastX: 0,&lt;br /&gt;
    lastTime: 0,&lt;br /&gt;
    releaseVelocity: 0,&lt;br /&gt;
    suppressClickUntil: 0,&lt;br /&gt;
    raf: null,&lt;br /&gt;
    pendingRotation: 0,&lt;br /&gt;
    snapTimer: null,&lt;br /&gt;
    inertiaRaf: null,&lt;br /&gt;
    navigateTimer: null,&lt;br /&gt;
    bound: false,&lt;br /&gt;
    boundElement: null,&lt;br /&gt;
    rotor: null,&lt;br /&gt;
    cx: 101,&lt;br /&gt;
    cy: 119,&lt;br /&gt;
    outerR: 109,&lt;br /&gt;
    innerR: 28,&lt;br /&gt;
    sectorAngle: 30,&lt;br /&gt;
    halfSector: 15,&lt;br /&gt;
    repeats: 8,&lt;br /&gt;
    dragSensitivity: 0.58,&lt;br /&gt;
    maxSpinVelocity: 1.75,&lt;br /&gt;
    minSpinVelocity: 0.055,&lt;br /&gt;
    spinDecel: 0.00185&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function createSidebarLanguageSvgEl(tag) {&lt;br /&gt;
    return document.createElementNS(SIDEBAR_LANG_SVG_NS, tag);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageIndex(index) {&lt;br /&gt;
    var length = sidebarLanguageState.order.length;&lt;br /&gt;
    var normalized = index % length;&lt;br /&gt;
    return normalized &amp;lt; 0 ? normalized + length : normalized;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || String(lang || &#039;&#039;).toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageDialName(lang) {&lt;br /&gt;
    return SIDEBAR_LANGUAGE_DIAL_LABELS[lang] || getSidebarLanguageName(lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function normalizeSidebarLanguageStatusValue(value) {&lt;br /&gt;
    value = String(value == null ? &#039;&#039; : value).toLowerCase().trim();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_STATUS_VALUES[value] ? value : &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusPageKey() {&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
&lt;br /&gt;
    return normalized || raw || &#039;대문&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusEntry() {&lt;br /&gt;
    var registry = sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    var pages = registry.pages &amp;amp;&amp;amp; typeof registry.pages === &#039;object&#039; ? registry.pages : registry;&lt;br /&gt;
    var raw = String(mw.config.get(&#039;wgPageName&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var normalized = normalizePageName(raw);&lt;br /&gt;
    var title = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).trim();&lt;br /&gt;
    var keys = [&lt;br /&gt;
        normalized,&lt;br /&gt;
        raw,&lt;br /&gt;
        raw.replace(/_/g, &#039; &#039;),&lt;br /&gt;
        normalized.replace(/ /g, &#039;_&#039;),&lt;br /&gt;
        title,&lt;br /&gt;
        title.replace(/_/g, &#039; &#039;)&lt;br /&gt;
    ];&lt;br /&gt;
    var i;&lt;br /&gt;
&lt;br /&gt;
    for (i = 0; i &amp;lt; keys.length; i += 1) {&lt;br /&gt;
        if (keys[i] &amp;amp;&amp;amp; pages[keys[i]] &amp;amp;&amp;amp; typeof pages[keys[i]] === &#039;object&#039;) {&lt;br /&gt;
            return pages[keys[i]];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatusOverride(lang) {&lt;br /&gt;
    var entry = getSidebarLanguageStatusEntry();&lt;br /&gt;
    return normalizeSidebarLanguageStatusValue(entry[lang]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function flushSidebarLanguageStatusCallbacks() {&lt;br /&gt;
    var callbacks = sidebarLanguageStatusCallbacks.slice();&lt;br /&gt;
    sidebarLanguageStatusCallbacks.length = 0;&lt;br /&gt;
&lt;br /&gt;
    callbacks.forEach(function(callback) {&lt;br /&gt;
        if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
            callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadSidebarLanguageStatusRegistry(callback, force) {&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        sidebarLanguageStatusCallbacks.push(callback);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoaded &amp;amp;&amp;amp; !force) {&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (sidebarLanguageStatusLoading) return;&lt;br /&gt;
&lt;br /&gt;
    sidebarLanguageStatusLoading = true;&lt;br /&gt;
&lt;br /&gt;
    $.ajax({&lt;br /&gt;
        url: mw.util.getUrl(SIDEBAR_LANGUAGE_STATUS_TITLE, {&lt;br /&gt;
            action: &#039;raw&#039;,&lt;br /&gt;
            ctype: &#039;application/json&#039;,&lt;br /&gt;
            _: String(Date.now())&lt;br /&gt;
        }),&lt;br /&gt;
        dataType: &#039;text&#039;,&lt;br /&gt;
        cache: false&lt;br /&gt;
    }).done(function(text) {&lt;br /&gt;
        var parsed = {};&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            parsed = text ? JSON.parse(text) : {};&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;LanguageStatus.json parse failed:&#039;, err);&lt;br /&gt;
            parsed = {};&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        sidebarLanguageStatusRegistry = parsed &amp;amp;&amp;amp; typeof parsed === &#039;object&#039; ? parsed : {};&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        sidebarLanguageStatusRegistry = {};&lt;br /&gt;
    }).always(function() {&lt;br /&gt;
        sidebarLanguageStatusLoaded = true;&lt;br /&gt;
        sidebarLanguageStatusLoading = false;&lt;br /&gt;
        flushSidebarLanguageStatusCallbacks();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.CLBI_LANGUAGE_STATUS = {&lt;br /&gt;
    title: SIDEBAR_LANGUAGE_STATUS_TITLE,&lt;br /&gt;
    languages: sidebarLanguageState.order.slice(),&lt;br /&gt;
    labels: SIDEBAR_LANGUAGE_LABELS,&lt;br /&gt;
    dialLabels: SIDEBAR_LANGUAGE_DIAL_LABELS,&lt;br /&gt;
    getPageKey: getSidebarLanguageStatusPageKey,&lt;br /&gt;
    getRegistry: function() {&lt;br /&gt;
        return sidebarLanguageStatusRegistry || {};&lt;br /&gt;
    },&lt;br /&gt;
    reload: function(callback) {&lt;br /&gt;
        sidebarLanguageStatusLoaded = false;&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            renderSidebarLanguageBox();&lt;br /&gt;
            if (typeof callback === &#039;function&#039;) callback(sidebarLanguageStatusRegistry);&lt;br /&gt;
        }, true);&lt;br /&gt;
    },&lt;br /&gt;
    refreshDial: function() {&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageMeta(lang) {&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var targetTitle = getLanguageTargetTitle(lang);&lt;br /&gt;
    var isCurrent = lang === currentLang;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        lang: lang,&lt;br /&gt;
        code: getLangShortCode(lang),&lt;br /&gt;
        name: getSidebarLanguageName(lang),&lt;br /&gt;
        dialName: getSidebarLanguageDialName(lang),&lt;br /&gt;
        targetTitle: targetTitle,&lt;br /&gt;
        isCurrent: isCurrent,&lt;br /&gt;
        canMove: !!targetTitle &amp;amp;&amp;amp; !isCurrent&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageStatus(meta) {&lt;br /&gt;
    var override;&lt;br /&gt;
&lt;br /&gt;
    if (!meta) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (meta.isCurrent) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-current&#039;,&lt;br /&gt;
            label: &#039;CURRENT&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override = getSidebarLanguageStatusOverride(meta.lang);&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;wip&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;WIP&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;unavailable&#039;) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: &#039;is-locked&#039;,&lt;br /&gt;
            label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: false&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (override === &#039;available&#039; || meta.targetTitle) {&lt;br /&gt;
        return {&lt;br /&gt;
            className: meta.targetTitle ? &#039;is-ready&#039; : &#039;is-locked&#039;,&lt;br /&gt;
            label: meta.targetTitle ? &#039;AVAILABLE&#039; : &#039;UNAVAILABLE&#039;,&lt;br /&gt;
            canApply: !!meta.targetTitle&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        className: &#039;is-locked&#039;,&lt;br /&gt;
        label: &#039;UNAVAILABLE&#039;,&lt;br /&gt;
        canApply: false&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguageRad(deg) {&lt;br /&gt;
    return (deg * Math.PI) / 180;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function sidebarLanguagePointAt(radius, deg) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var angle = sidebarLanguageRad(deg);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        x: state.cx + Math.sin(angle) * radius,&lt;br /&gt;
        y: state.cy - Math.cos(angle) * radius&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageSectorPath(start, end) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var p1 = sidebarLanguagePointAt(state.outerR, start);&lt;br /&gt;
    var p2 = sidebarLanguagePointAt(state.outerR, end);&lt;br /&gt;
    var p3 = sidebarLanguagePointAt(state.innerR, end);&lt;br /&gt;
    var p4 = sidebarLanguagePointAt(state.innerR, start);&lt;br /&gt;
    var largeArc = Math.abs(end - start) &amp;gt; 180 ? 1 : 0;&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;M&#039;, p1.x.toFixed(3), p1.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.outerR, state.outerR, 0, largeArc, 1, p2.x.toFixed(3), p2.y.toFixed(3),&lt;br /&gt;
        &#039;L&#039;, p3.x.toFixed(3), p3.y.toFixed(3),&lt;br /&gt;
        &#039;A&#039;, state.innerR, state.innerR, 0, largeArc, 0, p4.x.toFixed(3), p4.y.toFixed(3),&lt;br /&gt;
        &#039;Z&#039;&lt;br /&gt;
    ].join(&#039; &#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageShellPath() {&lt;br /&gt;
    return getSidebarLanguageSectorPath(-68, 68);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguageByStep(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        index: index,&lt;br /&gt;
        meta: getSidebarLanguageMeta(state.order[index])&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewIndex() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    return normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSidebarLanguagePreviewMeta() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    return getSidebarLanguageMeta(state.order[getSidebarLanguagePreviewIndex()]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeSidebarLanguageSector(step) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var item = getSidebarLanguageByStep(step);&lt;br /&gt;
    var group = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    var path = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    var label = createSidebarLanguageSvgEl(&#039;text&#039;);&lt;br /&gt;
    var labelY = state.cy - 78;&lt;br /&gt;
    var angle = step * state.sectorAngle;&lt;br /&gt;
&lt;br /&gt;
    group.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-group&#039;);&lt;br /&gt;
    group.setAttribute(&#039;data-step&#039;, String(step));&lt;br /&gt;
    group.setAttribute(&#039;data-index&#039;, String(item.index));&lt;br /&gt;
    group.setAttribute(&#039;data-lang&#039;, item.meta.lang);&lt;br /&gt;
    group.setAttribute(&#039;transform&#039;, &#039;rotate(&#039; + angle + &#039; &#039; + state.cx + &#039; &#039; + state.cy + &#039;)&#039;);&lt;br /&gt;
&lt;br /&gt;
    path.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector&#039;);&lt;br /&gt;
    path.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
&lt;br /&gt;
    label.setAttribute(&#039;class&#039;, &#039;sidebar-lang-sector-label&#039;);&lt;br /&gt;
    label.setAttribute(&#039;x&#039;, String(state.cx));&lt;br /&gt;
    label.setAttribute(&#039;y&#039;, String(labelY + 5));&lt;br /&gt;
    label.textContent = item.meta.dialName || item.meta.name;&lt;br /&gt;
&lt;br /&gt;
    group.appendChild(path);&lt;br /&gt;
    group.appendChild(label);&lt;br /&gt;
&lt;br /&gt;
    group.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        if (sidebarLanguageState.dragging || performance.now() &amp;lt; sidebarLanguageState.suppressClickUntil) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        snapSidebarLanguageToStep(parseInt(group.getAttribute(&#039;data-step&#039;) || &#039;0&#039;, 10), true);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return group;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageWheel() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var svg;&lt;br /&gt;
    var defs;&lt;br /&gt;
    var clip;&lt;br /&gt;
    var clipPath;&lt;br /&gt;
    var shadowBlur;&lt;br /&gt;
    var blur;&lt;br /&gt;
    var fixedDepthGradient;&lt;br /&gt;
    var shell;&lt;br /&gt;
    var clipped;&lt;br /&gt;
    var rotor;&lt;br /&gt;
    var fixedDepthPath;&lt;br /&gt;
    var fixedFocus;&lt;br /&gt;
    var shadowSoft;&lt;br /&gt;
    var shadowHard;&lt;br /&gt;
    var rim;&lt;br /&gt;
    var pointer;&lt;br /&gt;
    var tri;&lt;br /&gt;
    var line;&lt;br /&gt;
    var step;&lt;br /&gt;
&lt;br /&gt;
    if (!fan) return;&lt;br /&gt;
&lt;br /&gt;
    fan.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    svg = createSidebarLanguageSvgEl(&#039;svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fan-svg&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;viewBox&#039;, &#039;0 0 202 150&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;preserveAspectRatio&#039;, &#039;xMidYMid meet&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;role&#039;, &#039;img&#039;);&lt;br /&gt;
    svg.setAttribute(&#039;aria-label&#039;, &#039;언어 선택 다이얼&#039;);&lt;br /&gt;
&lt;br /&gt;
    defs = createSidebarLanguageSvgEl(&#039;defs&#039;);&lt;br /&gt;
&lt;br /&gt;
    clip = createSidebarLanguageSvgEl(&#039;clipPath&#039;);&lt;br /&gt;
    clip.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fan-clip&#039;);&lt;br /&gt;
    clipPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    clipPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    clip.appendChild(clipPath);&lt;br /&gt;
&lt;br /&gt;
    shadowBlur = createSidebarLanguageSvgEl(&#039;filter&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-shadow-blur&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;x&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;y&#039;, &#039;-20%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;width&#039;, &#039;140%&#039;);&lt;br /&gt;
    shadowBlur.setAttribute(&#039;height&#039;, &#039;140%&#039;);&lt;br /&gt;
    blur = createSidebarLanguageSvgEl(&#039;feGaussianBlur&#039;);&lt;br /&gt;
    blur.setAttribute(&#039;stdDeviation&#039;, &#039;3&#039;);&lt;br /&gt;
    shadowBlur.appendChild(blur);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthGradient = createSidebarLanguageSvgEl(&#039;linearGradient&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-language-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y1&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;x2&#039;, &#039;0&#039;);&lt;br /&gt;
    fixedDepthGradient.setAttribute(&#039;y2&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
    [&lt;br /&gt;
        [&#039;0%&#039;, &#039;#ffffff&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;34%&#039;, &#039;#ffffff&#039;, &#039;0.006&#039;],&lt;br /&gt;
        [&#039;58%&#039;, &#039;#000000&#039;, &#039;0.030&#039;],&lt;br /&gt;
        [&#039;100%&#039;, &#039;#000000&#039;, &#039;0.250&#039;]&lt;br /&gt;
    ].forEach(function(item) {&lt;br /&gt;
        var stop = createSidebarLanguageSvgEl(&#039;stop&#039;);&lt;br /&gt;
        stop.setAttribute(&#039;offset&#039;, item[0]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-color&#039;, item[1]);&lt;br /&gt;
        stop.setAttribute(&#039;stop-opacity&#039;, item[2]);&lt;br /&gt;
        fixedDepthGradient.appendChild(stop);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    defs.appendChild(clip);&lt;br /&gt;
    defs.appendChild(shadowBlur);&lt;br /&gt;
    defs.appendChild(fixedDepthGradient);&lt;br /&gt;
    svg.appendChild(defs);&lt;br /&gt;
&lt;br /&gt;
    shell = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;class&#039;, &#039;sidebar-lang-shell&#039;);&lt;br /&gt;
    shell.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shell);&lt;br /&gt;
&lt;br /&gt;
    clipped = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    clipped.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    rotor = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;id&#039;, &#039;clbi-sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
    rotor.setAttribute(&#039;class&#039;, &#039;sidebar-lang-wheel-rotor&#039;);&lt;br /&gt;
&lt;br /&gt;
    for (step = -state.repeats; step &amp;lt;= state.repeats; step += 1) {&lt;br /&gt;
        rotor.appendChild(makeSidebarLanguageSector(step));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    clipped.appendChild(rotor);&lt;br /&gt;
    svg.appendChild(clipped);&lt;br /&gt;
&lt;br /&gt;
    fixedDepthPath = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-depth&#039;);&lt;br /&gt;
    fixedDepthPath.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(fixedDepthPath);&lt;br /&gt;
&lt;br /&gt;
    fixedFocus = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-focus&#039;);&lt;br /&gt;
    fixedFocus.setAttribute(&#039;d&#039;, getSidebarLanguageSectorPath(-state.halfSector, state.halfSector));&lt;br /&gt;
    svg.appendChild(fixedFocus);&lt;br /&gt;
&lt;br /&gt;
    shadowSoft = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-soft&#039;);&lt;br /&gt;
    shadowSoft.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowSoft);&lt;br /&gt;
&lt;br /&gt;
    shadowHard = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;class&#039;, &#039;sidebar-lang-inner-shadow-hard&#039;);&lt;br /&gt;
    shadowHard.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(shadowHard);&lt;br /&gt;
&lt;br /&gt;
    rim = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;class&#039;, &#039;sidebar-lang-rim&#039;);&lt;br /&gt;
    rim.setAttribute(&#039;d&#039;, getSidebarLanguageShellPath());&lt;br /&gt;
    svg.appendChild(rim);&lt;br /&gt;
&lt;br /&gt;
    pointer = createSidebarLanguageSvgEl(&#039;g&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;class&#039;, &#039;sidebar-lang-fixed-pointer&#039;);&lt;br /&gt;
    pointer.setAttribute(&#039;clip-path&#039;, &#039;url(#clbi-sidebar-language-fan-clip)&#039;);&lt;br /&gt;
&lt;br /&gt;
    tri = createSidebarLanguageSvgEl(&#039;path&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-triangle&#039;);&lt;br /&gt;
    tri.setAttribute(&#039;d&#039;, &#039;M &#039; + (state.cx - 10) + &#039; 10 L &#039; + (state.cx + 10) + &#039; 10 L &#039; + state.cx + &#039; 26 Z&#039;);&lt;br /&gt;
    pointer.appendChild(tri);&lt;br /&gt;
&lt;br /&gt;
    line = createSidebarLanguageSvgEl(&#039;line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;class&#039;, &#039;sidebar-lang-pointer-line&#039;);&lt;br /&gt;
    line.setAttribute(&#039;x1&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;x2&#039;, String(state.cx));&lt;br /&gt;
    line.setAttribute(&#039;y1&#039;, &#039;24&#039;);&lt;br /&gt;
    line.setAttribute(&#039;y2&#039;, &#039;112&#039;);&lt;br /&gt;
    pointer.appendChild(line);&lt;br /&gt;
&lt;br /&gt;
    svg.appendChild(pointer);&lt;br /&gt;
    fan.appendChild(svg);&lt;br /&gt;
&lt;br /&gt;
    state.rotor = rotor;&lt;br /&gt;
    setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSidebarLanguageDial() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var meta = getSidebarLanguagePreviewMeta();&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
    var selectedValue = document.getElementById(&#039;clbi-sidebar-lang-selected-value&#039;);&lt;br /&gt;
    var availabilityPanel = document.getElementById(&#039;clbi-sidebar-lang-availability-panel&#039;);&lt;br /&gt;
    var availabilityValue = document.getElementById(&#039;clbi-sidebar-lang-availability-value&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (selectedValue) {&lt;br /&gt;
        selectedValue.textContent = meta.name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityPanel) {&lt;br /&gt;
        availabilityPanel.classList.remove(&#039;is-ready&#039;, &#039;is-current&#039;, &#039;is-locked&#039;);&lt;br /&gt;
        availabilityPanel.classList.add(status.className);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (availabilityValue) {&lt;br /&gt;
        availabilityValue.textContent = status.label;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (apply) {&lt;br /&gt;
        apply.classList.toggle(&#039;is-disabled&#039;, !status.canApply);&lt;br /&gt;
        apply.setAttribute(&#039;aria-disabled&#039;, status.canApply ? &#039;false&#039; : &#039;true&#039;);&lt;br /&gt;
        apply.setAttribute(&#039;aria-label&#039;, status.canApply ? (meta.name + &#039; 적용&#039;) : (meta.isCurrent ? &#039;현재 언어&#039; : &#039;사용할 수 없는 언어&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (selector) {&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-lang&#039;, meta.lang);&lt;br /&gt;
        selector.setAttribute(&#039;data-selected-code&#039;, meta.code);&lt;br /&gt;
        selector.classList.toggle(&#039;is-current&#039;, meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-ready&#039;, status.canApply);&lt;br /&gt;
        selector.classList.toggle(&#039;is-locked&#039;, !status.canApply &amp;amp;&amp;amp; !meta.isCurrent);&lt;br /&gt;
        selector.classList.toggle(&#039;is-dragging&#039;, !!state.dragging);&lt;br /&gt;
        selector.classList.toggle(&#039;is-spinning&#039;, !!state.inertiaRaf);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        meta: meta,&lt;br /&gt;
        status: status&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageRotation(value, animate) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.rotation = value;&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (!state.rotor) return;&lt;br /&gt;
&lt;br /&gt;
    if (animate) {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-snapping&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.rotor.style.transform = &#039;rotate(&#039; + state.rotation.toFixed(3) + &#039;deg)&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function requestSidebarLanguageRotation(value) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    state.pendingRotation = value;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) return;&lt;br /&gt;
&lt;br /&gt;
    state.raf = requestAnimationFrame(function() {&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
        setSidebarLanguageRotation(state.pendingRotation, false);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function cancelSidebarLanguageSpin() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    if (state.inertiaRaf) {&lt;br /&gt;
        cancelAnimationFrame(state.inertiaRaf);&lt;br /&gt;
        state.inertiaRaf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function finishSidebarLanguageSnap(nearestIndex, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
&lt;br /&gt;
    state.baseIndex = normalizeSidebarLanguageIndex(nearestIndex);&lt;br /&gt;
    state.selectedIndex = state.baseIndex;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-snapping is-dragging is-spinning&#039;);&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
&lt;br /&gt;
    if (typeof callback === &#039;function&#039;) {&lt;br /&gt;
        callback(getSidebarLanguageMeta(state.order[state.selectedIndex]));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageToStep(step, animate, callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var targetRotation = -step * state.sectorAngle;&lt;br /&gt;
    var nearestIndex = normalizeSidebarLanguageIndex(state.baseIndex + step);&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.selectedIndex = nearestIndex;&lt;br /&gt;
    setSidebarLanguageRotation(targetRotation, !!animate);&lt;br /&gt;
&lt;br /&gt;
    state.snapTimer = setTimeout(function() {&lt;br /&gt;
        finishSidebarLanguageSnap(nearestIndex, callback);&lt;br /&gt;
    }, animate ? 230 : 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function snapSidebarLanguageNearest(callback) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var step = Math.round(-state.rotation / state.sectorAngle);&lt;br /&gt;
    snapSidebarLanguageToStep(step, true, callback);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function startSidebarLanguageInertiaSpin(initialVelocity) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var velocity;&lt;br /&gt;
    var lastFrame;&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
&lt;br /&gt;
    velocity = Math.max(-state.maxSpinVelocity, Math.min(state.maxSpinVelocity, initialVelocity));&lt;br /&gt;
&lt;br /&gt;
    if (Math.abs(velocity) &amp;lt; state.minSpinVelocity) {&lt;br /&gt;
        snapSidebarLanguageNearest();&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-sidebar-lang-selector&#039;).addClass(&#039;is-spinning&#039;);&lt;br /&gt;
    lastFrame = performance.now();&lt;br /&gt;
&lt;br /&gt;
    function frame(now) {&lt;br /&gt;
        var dt = Math.min(34, Math.max(1, now - lastFrame));&lt;br /&gt;
        var sign = velocity &amp;lt; 0 ? -1 : 1;&lt;br /&gt;
        var nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        lastFrame = now;&lt;br /&gt;
        state.rotation += velocity * dt;&lt;br /&gt;
        setSidebarLanguageRotation(state.rotation, false);&lt;br /&gt;
&lt;br /&gt;
        nextSpeed = Math.max(0, Math.abs(velocity) - (state.spinDecel * dt));&lt;br /&gt;
        velocity = sign * nextSpeed;&lt;br /&gt;
&lt;br /&gt;
        if (nextSpeed &amp;lt;= state.minSpinVelocity) {&lt;br /&gt;
            state.inertiaRaf = null;&lt;br /&gt;
            $(&#039;#clbi-sidebar-lang-selector&#039;).removeClass(&#039;is-spinning&#039;);&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state.inertiaRaf = requestAnimationFrame(frame);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function scheduleSidebarLanguageNavigation(meta) {&lt;br /&gt;
    var status = getSidebarLanguageStatus(meta);&lt;br /&gt;
&lt;br /&gt;
    if (!meta || !status.canApply) return;&lt;br /&gt;
&lt;br /&gt;
    clearTimeout(sidebarLanguageState.navigateTimer);&lt;br /&gt;
    sidebarLanguageState.navigateTimer = setTimeout(function() {&lt;br /&gt;
        var title = getLanguageTargetTitle(meta.lang);&lt;br /&gt;
&lt;br /&gt;
        if (!title || meta.lang === getCurrentLang()) return;&lt;br /&gt;
&lt;br /&gt;
        window.location.href = buildWikiPath(title);&lt;br /&gt;
    }, 70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setSidebarLanguageSelection(lang) {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var index = state.order.indexOf(lang);&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;lt; 0) index = state.order.indexOf(getCurrentLang());&lt;br /&gt;
    if (index &amp;lt; 0) index = 0;&lt;br /&gt;
&lt;br /&gt;
    if (state.raf) {&lt;br /&gt;
        cancelAnimationFrame(state.raf);&lt;br /&gt;
        state.raf = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cancelSidebarLanguageSpin();&lt;br /&gt;
    clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
    state.currentLang = lang;&lt;br /&gt;
    state.baseIndex = index;&lt;br /&gt;
    state.selectedIndex = index;&lt;br /&gt;
    state.rotation = 0;&lt;br /&gt;
    state.dragging = false;&lt;br /&gt;
    state.dragMoved = false;&lt;br /&gt;
    state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
    renderSidebarLanguageWheel();&lt;br /&gt;
    updateSidebarLanguageDial();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveSidebarLanguageSelection(delta) {&lt;br /&gt;
    snapSidebarLanguageToStep(-delta, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindSidebarLanguageSelector() {&lt;br /&gt;
    var state = sidebarLanguageState;&lt;br /&gt;
    var selector = document.getElementById(&#039;clbi-sidebar-lang-selector&#039;);&lt;br /&gt;
    var fan = document.getElementById(&#039;clbi-sidebar-lang-fan&#039;);&lt;br /&gt;
    var apply = document.getElementById(&#039;clbi-sidebar-lang-apply&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!selector || !fan || !apply) return;&lt;br /&gt;
&lt;br /&gt;
    if (state.bound &amp;amp;&amp;amp; state.boundElement === selector) return;&lt;br /&gt;
&lt;br /&gt;
    state.bound = true;&lt;br /&gt;
    state.boundElement = selector;&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerdown&#039;, function(e) {&lt;br /&gt;
        cancelSidebarLanguageSpin();&lt;br /&gt;
        clearTimeout(state.snapTimer);&lt;br /&gt;
&lt;br /&gt;
        state.dragging = true;&lt;br /&gt;
        state.dragMoved = false;&lt;br /&gt;
        state.dragStartX = e.clientX;&lt;br /&gt;
        state.dragStartY = e.clientY || 0;&lt;br /&gt;
        state.dragStartRotation = state.rotation;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = performance.now();&lt;br /&gt;
        state.releaseVelocity = 0;&lt;br /&gt;
&lt;br /&gt;
        selector.classList.add(&#039;is-dragging&#039;);&lt;br /&gt;
        selector.classList.remove(&#039;is-snapping&#039;);&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
        Vertical page scrolling must stay available when the pointer starts on&lt;br /&gt;
        the language dial. Capture and preventDefault are delayed until a&lt;br /&gt;
        horizontal drag is confirmed.&lt;br /&gt;
        */&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointermove&#039;, function(e) {&lt;br /&gt;
        var now;&lt;br /&gt;
        var totalDx;&lt;br /&gt;
        var totalDy;&lt;br /&gt;
        var frameDx;&lt;br /&gt;
        var dt;&lt;br /&gt;
        var instantVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        totalDx = e.clientX - state.dragStartX;&lt;br /&gt;
        totalDy = (e.clientY || 0) - state.dragStartY;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragAxis &amp;amp;&amp;amp; (Math.abs(totalDx) &amp;gt; 4 || Math.abs(totalDy) &amp;gt; 4)) {&lt;br /&gt;
            state.dragAxis = Math.abs(totalDx) &amp;gt;= Math.abs(totalDy) ? &#039;x&#039; : &#039;y&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (state.dragAxis === &#039;y&#039;) {&lt;br /&gt;
                state.dragging = false;&lt;br /&gt;
                state.dragMoved = false;&lt;br /&gt;
                state.dragAxis = null;&lt;br /&gt;
                state.pointerCaptured = false;&lt;br /&gt;
                selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (fan.setPointerCapture &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
                try {&lt;br /&gt;
                    fan.setPointerCapture(e.pointerId);&lt;br /&gt;
                    state.pointerCaptured = true;&lt;br /&gt;
                } catch (err) {&lt;br /&gt;
                    state.pointerCaptured = false;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragAxis !== &#039;x&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        now = performance.now();&lt;br /&gt;
        frameDx = e.clientX - state.lastX;&lt;br /&gt;
        dt = Math.max(1, now - state.lastTime);&lt;br /&gt;
&lt;br /&gt;
        if (Math.abs(totalDx) &amp;gt; 3) state.dragMoved = true;&lt;br /&gt;
&lt;br /&gt;
        instantVelocity = (frameDx * state.dragSensitivity) / dt;&lt;br /&gt;
        state.releaseVelocity = (state.releaseVelocity * 0.62) + (instantVelocity * 0.38);&lt;br /&gt;
        state.lastX = e.clientX;&lt;br /&gt;
        state.lastTime = now;&lt;br /&gt;
&lt;br /&gt;
        requestSidebarLanguageRotation(state.dragStartRotation + totalDx * state.dragSensitivity);&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function finishDrag(e) {&lt;br /&gt;
        var velocityAge;&lt;br /&gt;
        var throwVelocity;&lt;br /&gt;
        var wasHorizontal;&lt;br /&gt;
&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        wasHorizontal = state.dragAxis === &#039;x&#039;;&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (fan.releasePointerCapture &amp;amp;&amp;amp; state.pointerCaptured &amp;amp;&amp;amp; e &amp;amp;&amp;amp; e.pointerId != null) {&lt;br /&gt;
            try { fan.releasePointerCapture(e.pointerId); } catch (err) {}&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
&lt;br /&gt;
        if (!wasHorizontal &amp;amp;&amp;amp; !state.dragMoved) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        velocityAge = performance.now() - state.lastTime;&lt;br /&gt;
        throwVelocity = velocityAge &amp;gt; 120 ? 0 : state.releaseVelocity;&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(throwVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            startSidebarLanguageInertiaSpin(throwVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fan.addEventListener(&#039;pointerup&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;pointercancel&#039;, finishDrag);&lt;br /&gt;
    fan.addEventListener(&#039;lostpointercapture&#039;, function() {&lt;br /&gt;
        if (!state.dragging) return;&lt;br /&gt;
&lt;br /&gt;
        state.dragging = false;&lt;br /&gt;
        state.pointerCaptured = false;&lt;br /&gt;
        state.dragAxis = null;&lt;br /&gt;
        selector.classList.remove(&#039;is-dragging&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (state.dragMoved &amp;amp;&amp;amp; Math.abs(state.releaseVelocity) &amp;gt;= state.minSpinVelocity) {&lt;br /&gt;
            state.suppressClickUntil = performance.now() + 180;&lt;br /&gt;
            startSidebarLanguageInertiaSpin(state.releaseVelocity);&lt;br /&gt;
        } else {&lt;br /&gt;
            snapSidebarLanguageNearest();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    apply.addEventListener(&#039;click&#039;, function(e) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
        snapSidebarLanguageNearest(function(meta) {&lt;br /&gt;
            scheduleSidebarLanguageNavigation(meta);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    selector.addEventListener(&#039;keydown&#039;, function(e) {&lt;br /&gt;
        if (e.key === &#039;ArrowLeft&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(-1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;ArrowRight&#039;) {&lt;br /&gt;
            moveSidebarLanguageSelection(1);&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e.key === &#039;Enter&#039; || e.key === &#039; &#039;) {&lt;br /&gt;
            apply.click();&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSidebarLanguageBox() {&lt;br /&gt;
    bindSidebarLanguageSelector();&lt;br /&gt;
    setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
&lt;br /&gt;
    if (!sidebarLanguageStatusLoaded) {&lt;br /&gt;
        loadSidebarLanguageStatusRegistry(function() {&lt;br /&gt;
            setSidebarLanguageSelection(getCurrentLang());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadRecentChangesList(targetSelector, limit) {&lt;br /&gt;
    var $target = $(targetSelector);&lt;br /&gt;
&lt;br /&gt;
    if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
    var isNewsList = $target.closest(&#039;.clbi-left-news-box&#039;).length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.html((t &amp;amp;&amp;amp; t.loading) ? t.loading : &#039;불러오는 중...&#039;);&lt;br /&gt;
&lt;br /&gt;
    $.getJSON(&lt;br /&gt;
        &#039;/api.php?action=query&amp;amp;list=recentchanges&amp;amp;rclimit=&#039; + encodeURIComponent(limit || 5) + &#039;&amp;amp;rcprop=title|timestamp|user&amp;amp;format=json&amp;amp;rcnamespace=0&amp;amp;rctype=edit|new&#039;,&lt;br /&gt;
        function(data) {&lt;br /&gt;
            var items = data &amp;amp;&amp;amp; data.query ? data.query.recentchanges : [];&lt;br /&gt;
            var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (!items || !items.length) {&lt;br /&gt;
                $target.html(&#039;표시할 변경 사항이 없습니다.&#039;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $.each(items, function(i, item) {&lt;br /&gt;
                var label = timeAgo(item.timestamp);&lt;br /&gt;
                var title = item.title || &#039;&#039;;&lt;br /&gt;
                var userName = item.user || &#039;Unknown&#039;;&lt;br /&gt;
                var pageHref = buildWikiPath(title);&lt;br /&gt;
                var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(userName) + &#039;.png&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (isNewsList) {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;news-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img class=&amp;quot;news-recent-avatar&amp;quot; src=&amp;quot;&#039; + escapeHtml(avatarSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;news-recent-main&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;div class=&amp;quot;news-recent-meta&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    &#039;&amp;lt;span class=&amp;quot;news-recent-user&amp;quot;&amp;gt;@&#039; + escapeHtml(userName) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    html +=&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;clbi-recent-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;clbi-recent-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;a href=&amp;quot;&#039; + escapeHtml(pageHref) + &#039;&amp;quot; class=&amp;quot;clbi-recent-title&amp;quot;&amp;gt;&#039; + escapeHtml(title) + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;clbi-recent-time&amp;quot;&amp;gt;&#039; + escapeHtml(label) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $target.html(html);&lt;br /&gt;
&lt;br /&gt;
            $target.find(isNewsList ? &#039;.news-recent-item&#039; : &#039;.clbi-recent-item&#039;).each(function() {&lt;br /&gt;
                var wrap = $(this).find(isNewsList ? &#039;.news-recent-title-wrap&#039; : &#039;.clbi-recent-title-wrap&#039;);&lt;br /&gt;
                var title = $(this).find(isNewsList ? &#039;.news-recent-title&#039; : &#039;.clbi-recent-title&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (!wrap.length || !title.length) return;&lt;br /&gt;
&lt;br /&gt;
                var wrapW = wrap.width();&lt;br /&gt;
                var titleW = title[0].scrollWidth;&lt;br /&gt;
&lt;br /&gt;
                if (titleW &amp;gt; wrapW + 20) {&lt;br /&gt;
                    var duration = titleW / 40;&lt;br /&gt;
&lt;br /&gt;
                    title.css({&lt;br /&gt;
                        animation: &#039;clbi-scroll &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
                        &#039;--scroll-dist&#039;: &#039;-&#039; + (titleW - wrapW + 8) + &#039;px&#039;&lt;br /&gt;
                    });&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    ).fail(function() {&lt;br /&gt;
        var lang = getCurrentLang();&lt;br /&gt;
        var t = (window.LANG &amp;amp;&amp;amp; window.LANG[lang]) ? window.LANG[lang] : (window.LANG ? window.LANG.ko : null);&lt;br /&gt;
&lt;br /&gt;
        $target.html((t &amp;amp;&amp;amp; t.loadFail) ? t.loadFail : &#039;불러오기 실패&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 국가_및_조합 전용 왼쪽 사이드바 이미지&lt;br /&gt;
function updateLeftSidebarNationsImage() {&lt;br /&gt;
    $(&#039;#clbi-left-nations-image&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setProfileActionLabel(selector, text) {&lt;br /&gt;
    var target = $(selector);&lt;br /&gt;
    var label = target.find(&#039;.profile-action-label&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (label.length) {&lt;br /&gt;
        label.text(text);&lt;br /&gt;
    } else {&lt;br /&gt;
        target.text(text);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 사이드바 업데이트&lt;br /&gt;
function updateSidebar() {&lt;br /&gt;
    if (!window.LANG) {&lt;br /&gt;
        setTimeout(updateSidebar, 100);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
&lt;br /&gt;
    var newsTitle = t.news || &#039;뉴스&#039;;&lt;br /&gt;
    var changelogTitle = t.changelog || &#039;체인지로그&#039;;&lt;br /&gt;
    var recentTitle = t.recentChanges || &#039;최근 변경&#039;;&lt;br /&gt;
    var languageTitle = t.language || &#039;언어&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-language&#039;).text(languageTitle);&lt;br /&gt;
    renderSidebarLanguageBox();&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-left-news&#039;).text(newsTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
    $(&#039;#clbi-left-news-recent-main&#039;).text(recentTitle);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#clbi-title-search a&#039;).text(t.search);&lt;br /&gt;
    $(&#039;#clbi-search-input&#039;).attr(&#039;placeholder&#039;, t.search + &#039;...&#039;);&lt;br /&gt;
    $(&#039;#clbi-title-recent a&#039;).text(recentTitle);&lt;br /&gt;
    $(&#039;#clbi-title-guide-label&#039;).text(t.guide);&lt;br /&gt;
    $(&#039;#clbi-guide-link&#039;).text(t.getStarted);&lt;br /&gt;
    $(&#039;#clbi-title-links-label&#039;).text(t.links);&lt;br /&gt;
&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-contribution&#039;, t.contribution);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-watchlist&#039;, t.watchlist);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-preferences&#039;, t.preferences);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-logout&#039;, t.logout);&lt;br /&gt;
    setProfileActionLabel(&#039;#clbi-btn-login&#039;, t.login);&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var specialPage = String(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
$(&#039;#clbi-left-news-changelog-main&#039;).text(changelogTitle);&lt;br /&gt;
$(&#039;#clbi-left-news-recent-title&#039;).text(&#039;RECENT CHANGES&#039;);&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.clbi-user-btn&#039;).removeClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;Contributions&#039; ||&lt;br /&gt;
        specialPage === &#039;기여&#039; ||&lt;br /&gt;
        pageName.indexOf(&#039;특수:기여&#039;) === 0 ||&lt;br /&gt;
        pageName.indexOf(&#039;Special:Contributions&#039;) === 0&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-contribution&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (specialPage === &#039;Watchlist&#039;) {&lt;br /&gt;
        $(&#039;#clbi-btn-watchlist&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
        specialPage === &#039;설정&#039; ||&lt;br /&gt;
        pageName === &#039;특수:설정&#039; ||&lt;br /&gt;
        pageName === &#039;Special:설정&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        $(&#039;#clbi-btn-preferences&#039;).addClass(&#039;clbi-user-btn-active&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.toggleBtn&#039;).each(function() {&lt;br /&gt;
        var btn = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (!$(&#039;#&#039; + btn.data(&#039;target&#039;)).hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            btn.text(t.expand);&lt;br /&gt;
        } else {&lt;br /&gt;
            btn.text(t.collapse);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    updateLeftSidebarNationsImage();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function isMediaWikiSystemAssetPage() {&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
&lt;br /&gt;
    if (namespaceNumber !== 8) return false;&lt;br /&gt;
&lt;br /&gt;
    return /\.(css|js)$/i.test(pageName);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeSystemDocIndicator() {&lt;br /&gt;
    $(&#039;body&#039;).removeClass(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
    $(&#039;#clbi-system-doc-indicator-row&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderSystemDocIndicator() {&lt;br /&gt;
    removeSystemDocIndicator();&lt;br /&gt;
&lt;br /&gt;
    if (!isMediaWikiSystemAssetPage()) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var extMatch = pageName.match(/\.(css|js)$/i);&lt;br /&gt;
    var ext = extMatch ? extMatch[1].toUpperCase() : &#039;DOC&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;clbi-system-doc-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var $row = $(&#039;&amp;lt;div id=&amp;quot;clbi-system-doc-indicator-row&amp;quot; class=&amp;quot;clbi-system-doc-indicator-row&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    var $box = $(&#039;&amp;lt;div class=&amp;quot;clbi-system-doc-indicator&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    var $meta = $(&#039;&amp;lt;div class=&amp;quot;clbi-system-doc-meta&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    var $label = $(&#039;&amp;lt;span class=&amp;quot;clbi-system-doc-label&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&#039;).text(&#039;SYSTEM DOCUMENT&#039;);&lt;br /&gt;
    var $type = $(&#039;&amp;lt;span class=&amp;quot;clbi-system-doc-type&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&#039;).text(ext);&lt;br /&gt;
    var $title = $(&#039;&amp;lt;div class=&amp;quot;clbi-system-doc-title&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;).text(pageName);&lt;br /&gt;
&lt;br /&gt;
    $meta.append($label).append($type);&lt;br /&gt;
    $box.append($meta).append($title);&lt;br /&gt;
    $row.append($box);&lt;br /&gt;
&lt;br /&gt;
    var $anchor = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    if ($anchor.length) {&lt;br /&gt;
        $anchor.before($row);&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).prepend($row);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function canShowContentTools() {&lt;br /&gt;
    // 비로그인 사용자는 편집/역사/공유 버튼을 숨김&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki가 현재 문서를 편집 가능하지 않다고 판단하면 숨김&lt;br /&gt;
    var isEditable = mw.config.get(&#039;wgIsProbablyEditable&#039;);&lt;br /&gt;
    if (isEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var relevantEditable = mw.config.get(&#039;wgRelevantPageIsProbablyEditable&#039;);&lt;br /&gt;
    if (relevantEditable === false) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function moveCatlinksToBottom() {&lt;br /&gt;
    var main = $(&#039;.liberty-content-main&#039;);&lt;br /&gt;
    var parserOutput = $(&#039;.liberty-content-main .mw-parser-output&#039;).first();&lt;br /&gt;
    var catlinks = $(&#039;.catlinks&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!main.length || !catlinks.length) return;&lt;br /&gt;
&lt;br /&gt;
    catlinks.each(function () {&lt;br /&gt;
        var cat = $(this);&lt;br /&gt;
&lt;br /&gt;
        if (parserOutput.length) {&lt;br /&gt;
            cat.appendTo(parserOutput);&lt;br /&gt;
        } else {&lt;br /&gt;
            cat.appendTo(main);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 대문 스타일&lt;br /&gt;
function initCategoryNavIfAvailable(root) {&lt;br /&gt;
    /*&lt;br /&gt;
    CategoryNav.js는 대문 카테고리 네비를 SVG로 생성한다.&lt;br /&gt;
&lt;br /&gt;
    Common.js가 SPA로 본문을 갈아끼운 뒤에는 MediaWiki 원래 페이지 로드와 달리&lt;br /&gt;
    CategoryNav.js의 초기 DOMContentLoaded만으로는 새 mount를 다시 잡지 못할 수 있다.&lt;br /&gt;
    CategoryNav.js 자체도 mw.hook(&#039;wikipage.content&#039;)를 듣지만, 로드 순서와 SPA 타이밍이&lt;br /&gt;
    엇갈릴 수 있으므로 Common.js 쪽에서도 존재 여부를 확인한 뒤 한 번 더 호출한다.&lt;br /&gt;
&lt;br /&gt;
    이 함수는 CategoryNav.js가 아직 로드되지 않았으면 아무 것도 하지 않는다.&lt;br /&gt;
    */&lt;br /&gt;
    if (&lt;br /&gt;
        window.CLBI &amp;amp;&amp;amp;&lt;br /&gt;
        window.CLBI.categoryNav &amp;amp;&amp;amp;&lt;br /&gt;
        typeof window.CLBI.categoryNav.init === &#039;function&#039;&lt;br /&gt;
    ) {&lt;br /&gt;
        window.CLBI.categoryNav.init(root || document);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeLegacyMainPageHero() {&lt;br /&gt;
    /*&lt;br /&gt;
    기존 대문 전용 레거시 요소 정리&lt;br /&gt;
    -----------------------------------------&lt;br /&gt;
    이전 대문 구조에서는 Common.js가 본문 바깥에 #clbi-main-logo를 직접 삽입하고,&lt;br /&gt;
    본문 안의 #clbi-main-crt-hero를 #clbi-main-crt-hero-wrap으로 감싸서&lt;br /&gt;
    .liberty-content-main 위쪽으로 재배치했다.&lt;br /&gt;
&lt;br /&gt;
    새 대문은 본문 내부의 .main-portal이 로고, 알림, 카테고리 네비, 이미지 피드,&lt;br /&gt;
    방명록, 상태 패널을 모두 담당한다. 따라서 Common.js가 별도 로고나 CRT 래퍼를&lt;br /&gt;
    삽입하면 새 로고/콘텐츠와 중복된다.&lt;br /&gt;
&lt;br /&gt;
    여기서는 JS가 만들던 바깥 로고와 CRT 래퍼를 제거하고, 예전 대문 원본이나&lt;br /&gt;
    캐시된 렌더 결과에 남아 있을 수 있는 #clbi-main-crt-hero도 제거한다.&lt;br /&gt;
    */&lt;br /&gt;
    $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
    $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function applyMainPageStyle() {&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    if (specialPage === &#039;Preferences&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var pageName = normalizePageName(mw.config.get(&#039;wgPageName&#039;));&lt;br /&gt;
    var namespaceNumber = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var isMainPage = (pageName === &#039;대문&#039;);&lt;br /&gt;
    var isUserProfilePage = (namespaceNumber === 2);&lt;br /&gt;
    var isScreenDoc = ($(&#039;.screen-header&#039;).length &amp;gt; 0);&lt;br /&gt;
    var isSystemAssetPage = isMediaWikiSystemAssetPage();&lt;br /&gt;
    var hideTools = (isMainPage || isUserProfilePage || isSystemAssetPage || !canShowContentTools());&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, isUserProfilePage);&lt;br /&gt;
&lt;br /&gt;
    // 모든 문서에서 분류 바를 본문 컨테이너 아래로 이동&lt;br /&gt;
    moveCatlinksToBottom();&lt;br /&gt;
&lt;br /&gt;
    if (isMainPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 새 대문은 .main-portal 본문 구조가 로고/히어로를 담당한다.&lt;br /&gt;
        // Common.js의 구식 바깥 로고/CRT 재배치 루틴은 사용하지 않는다.&lt;br /&gt;
        removeLegacyMainPageHero();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content&#039;).addClass(&#039;content-tools-hidden&#039;);&lt;br /&gt;
&lt;br /&gt;
        initCategoryNavIfAvailable(document);&lt;br /&gt;
        removeSystemDocIndicator();&lt;br /&gt;
&lt;br /&gt;
    } else if (isUserProfilePage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content&#039;).addClass(&#039;content-tools-hidden&#039;);&lt;br /&gt;
        removeSystemDocIndicator();&lt;br /&gt;
&lt;br /&gt;
    } else if (isSystemAssetPage) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content&#039;).addClass(&#039;content-tools-hidden&#039;);&lt;br /&gt;
&lt;br /&gt;
        renderSystemDocIndicator();&lt;br /&gt;
&lt;br /&gt;
    } else if (isScreenDoc) {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main&#039;).addClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
        if ($(&#039;#clbi-tools-box&#039;).length === 0 &amp;amp;&amp;amp; canShowContentTools()) {&lt;br /&gt;
            var $toolsBox = $(&#039;&amp;lt;div id=&amp;quot;clbi-tools-box&amp;quot; class=&amp;quot;clbi-left-box&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsTitle = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;clbi-icon&amp;quot; style=&amp;quot;--icon:var(--ic-ui-003)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; 관리&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            var $toolsContent = $(&#039;&amp;lt;div class=&amp;quot;clbi-left-content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
            $toolsContent.append($(&#039;.content-tools .btn-group&#039;).clone(true));&lt;br /&gt;
            $toolsBox.append($toolsTitle).append($toolsContent);&lt;br /&gt;
            $(&#039;#clbi-left-sidebar&#039;).append($toolsBox);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content&#039;).addClass(&#039;content-tools-hidden&#039;);&lt;br /&gt;
        removeSystemDocIndicator();&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        $(&#039;.liberty-content-header&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.mw-page-title-main, .mw-page-title-namespace, .mw-page-title-separator&#039;).removeClass(&#039;clbi-hide&#039;);&lt;br /&gt;
        $(&#039;.catlinks&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content-main&#039;).css(&#039;border-radius&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
        $(&#039;#clbi-main-logo&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-main-crt-hero-wrap&#039;).remove();&lt;br /&gt;
        $(&#039;#clbi-tools-box&#039;).remove();&lt;br /&gt;
        removeSystemDocIndicator();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!isUserProfilePage) {&lt;br /&gt;
        $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
        $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hideTools) {&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;none&#039;);&lt;br /&gt;
        $(&#039;.liberty-content&#039;).addClass(&#039;content-tools-hidden&#039;);&lt;br /&gt;
    } else if (!isScreenDoc &amp;amp;&amp;amp; !isUserProfilePage) {&lt;br /&gt;
        $(&#039;.content-tools&#039;).css(&#039;display&#039;, &#039;&#039;);&lt;br /&gt;
        $(&#039;.liberty-content&#039;).removeClass(&#039;content-tools-hidden&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    updateSidebar();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 본문 기본 목차 제거&lt;br /&gt;
function removeNativeTocFromContent() {&lt;br /&gt;
    $(&#039;.liberty-content-main #toc, .liberty-content-main .toc&#039;).remove();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 ID 가져오기&lt;br /&gt;
function getHeadingId(heading) {&lt;br /&gt;
    if (heading.id) {&lt;br /&gt;
        return heading.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline[id]&#039;);&lt;br /&gt;
    if (headline &amp;amp;&amp;amp; headline.id) {&lt;br /&gt;
        return headline.id;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: MediaWiki 문단 제목 텍스트 가져오기&lt;br /&gt;
function getHeadingText(heading) {&lt;br /&gt;
    var headline = heading.querySelector(&#039;.mw-headline&#039;);&lt;br /&gt;
    var source = headline || heading;&lt;br /&gt;
    var clone = source.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    $(clone).find(&#039;.mw-editsection, .mw-editsection-bracket, .mw-editsection-divider&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    return (clone.textContent || &#039;&#039;)&lt;br /&gt;
        .replace(/\s+/g, &#039; &#039;)&lt;br /&gt;
        .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 왼쪽 목차: 긴 제목에 자동 스크롤 적용&lt;br /&gt;
function initTocTitleScroll(root) {&lt;br /&gt;
    var $items = root&lt;br /&gt;
        ? $(root).find(&#039;.toc-scroll-text&#039;)&lt;br /&gt;
        : $(&#039;#side-toc-box .toc-scroll-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    $items.each(function () {&lt;br /&gt;
        var $text = $(this);&lt;br /&gt;
        var $wrap = $text.closest(&#039;.toc-scroll-wrap&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$wrap.length) return;&lt;br /&gt;
&lt;br /&gt;
        var wrapW = Math.floor($wrap.width());&lt;br /&gt;
        var textW = Math.ceil(this.scrollWidth);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 레이아웃 계산이 끝나지 않았으면 이번 실행에서는 건드리지 않는다.&lt;br /&gt;
        if (!wrapW || !textW) return;&lt;br /&gt;
&lt;br /&gt;
        if (textW &amp;lt;= wrapW + 12) {&lt;br /&gt;
            // 왼쪽 목차: 칸을 넘지 않는 제목은 전체 텍스트를 그대로 보여준다.&lt;br /&gt;
            $wrap.removeClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
            if ($text.data(&#039;toc-scroll-enabled&#039;)) {&lt;br /&gt;
                $text.css({&lt;br /&gt;
                    animation: &#039;&#039;,&lt;br /&gt;
                    &#039;animation-delay&#039;: &#039;&#039;,&lt;br /&gt;
                    &#039;--scroll-dist&#039;: &#039;&#039;&lt;br /&gt;
                });&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-enabled&#039;);&lt;br /&gt;
                $text.removeData(&#039;toc-scroll-key&#039;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var scrollDist = &#039;-&#039; + (textW - wrapW + 10) + &#039;px&#039;;&lt;br /&gt;
        var duration = Math.max(7, textW / 38) * 1.25;&lt;br /&gt;
        var scrollKey = scrollDist + &#039;|&#039; + duration;&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목에는 오른쪽 페이드와 스크롤을 적용한다.&lt;br /&gt;
        $wrap.addClass(&#039;is-scrolling&#039;);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 같은 값으로 이미 적용된 애니메이션은 다시 초기화하지 않는다.&lt;br /&gt;
        if ($text.data(&#039;toc-scroll-key&#039;) === scrollKey) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $text.data(&#039;toc-scroll-enabled&#039;, true);&lt;br /&gt;
        $text.data(&#039;toc-scroll-key&#039;, scrollKey);&lt;br /&gt;
&lt;br /&gt;
        $text.css({&lt;br /&gt;
            // 왼쪽 목차: 페이지 진입 직후에는 잠시 읽을 시간을 준 뒤 흐르게 한다.&lt;br /&gt;
            animation: &#039;toc-scroll-blink-reset &#039; + duration + &#039;s linear infinite&#039;,&lt;br /&gt;
            &#039;animation-delay&#039;: &#039;1s&#039;,&lt;br /&gt;
            &#039;--scroll-dist&#039;: scrollDist&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 목차를 왼쪽 사이드바에 새로 생성&lt;br /&gt;
function moveTocToLeftSidebar() {&lt;br /&gt;
    // 왼쪽 목차: MediaWiki가 만든 원래 목차는 본문에서 제거한다.&lt;br /&gt;
    removeNativeTocFromContent();&lt;br /&gt;
&lt;br /&gt;
    var leftSidebar = document.getElementById(&#039;clbi-left-sidebar&#039;);&lt;br /&gt;
    if (!leftSidebar) return;&lt;br /&gt;
&lt;br /&gt;
    var content =&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main .mw-parser-output&#039;) ||&lt;br /&gt;
        document.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!content) return;&lt;br /&gt;
&lt;br /&gt;
    var headings = Array.prototype.slice.call(&lt;br /&gt;
        content.querySelectorAll(&#039;h2, h3&#039;)&lt;br /&gt;
    ).filter(function (heading) {&lt;br /&gt;
        if (heading.closest(&#039;#toc, .toc, #side-toc-box&#039;)) return false;&lt;br /&gt;
&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
&lt;br /&gt;
        if (!id || !text) return false;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var tocKey = headings.map(function (heading) {&lt;br /&gt;
        return getHeadingId(heading) + &#039;|&#039; + getHeadingText(heading);&lt;br /&gt;
    }).join(&#039;||&#039;);&lt;br /&gt;
&lt;br /&gt;
    var existingBox = document.getElementById(&#039;side-toc-box&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 같은 문서에서 같은 목차를 이미 만들었다면 다시 지우고 만들지 않는다.&lt;br /&gt;
    if (existingBox &amp;amp;&amp;amp; existingBox.getAttribute(&#039;data-toc-key&#039;) === tocKey) {&lt;br /&gt;
        initTocTitleScroll(existingBox);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (existingBox) {&lt;br /&gt;
        existingBox.remove();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!headings.length) return;&lt;br /&gt;
&lt;br /&gt;
    var tocBox = document.createElement(&#039;div&#039;);&lt;br /&gt;
    tocBox.className = &#039;clbi-left-box&#039;;&lt;br /&gt;
    tocBox.id = &#039;side-toc-box&#039;;&lt;br /&gt;
    tocBox.setAttribute(&#039;data-toc-key&#039;, tocKey);&lt;br /&gt;
&lt;br /&gt;
    var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
    title.className = &#039;clbi-left-title&#039;;&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: 박스 제목은 Lang.js의 현재 UI 언어를 따른다.&lt;br /&gt;
    var currentLang = getCurrentLang();&lt;br /&gt;
    var t = (window.LANG &amp;amp;&amp;amp; window.LANG[currentLang]) ? window.LANG[currentLang] : window.LANG.ko;&lt;br /&gt;
    var tocTitleText = (t &amp;amp;&amp;amp; t.toc) ? t.toc : &#039;목차&#039;;&lt;br /&gt;
&lt;br /&gt;
    title.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LIST + &#039;&amp;lt;/span&amp;gt; &#039; + tocTitleText;&lt;br /&gt;
&lt;br /&gt;
    var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
    body.className = &#039;clbi-left-content toc-sidebar-content&#039;;&lt;br /&gt;
&lt;br /&gt;
    var list = document.createElement(&#039;ul&#039;);&lt;br /&gt;
    list.className = &#039;generated-toc&#039;;&lt;br /&gt;
&lt;br /&gt;
    headings.forEach(function (heading) {&lt;br /&gt;
        var id = getHeadingId(heading);&lt;br /&gt;
        var text = getHeadingText(heading);&lt;br /&gt;
        var level = heading.tagName.toLowerCase() === &#039;h3&#039; ? 3 : 2;&lt;br /&gt;
&lt;br /&gt;
        var item = document.createElement(&#039;li&#039;);&lt;br /&gt;
        item.className = &#039;toc-level-&#039; + level;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.setAttribute(&#039;href&#039;, &#039;#&#039; + id);&lt;br /&gt;
&lt;br /&gt;
        // 왼쪽 목차: 긴 제목 스크롤을 위해 텍스트를 별도 span으로 감싼다.&lt;br /&gt;
        var textWrap = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textWrap.className = &#039;toc-scroll-wrap&#039;;&lt;br /&gt;
&lt;br /&gt;
        var textSpan = document.createElement(&#039;span&#039;);&lt;br /&gt;
        textSpan.className = &#039;toc-scroll-text&#039;;&lt;br /&gt;
        textSpan.textContent = text;&lt;br /&gt;
&lt;br /&gt;
        textWrap.appendChild(textSpan);&lt;br /&gt;
        link.appendChild(textWrap);&lt;br /&gt;
&lt;br /&gt;
        item.appendChild(link);&lt;br /&gt;
        list.appendChild(item);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    body.appendChild(list);&lt;br /&gt;
    tocBox.appendChild(title);&lt;br /&gt;
    tocBox.appendChild(body);&lt;br /&gt;
    leftSidebar.appendChild(tocBox);&lt;br /&gt;
&lt;br /&gt;
    // 왼쪽 목차: DOM 배치가 끝난 뒤 긴 제목 스크롤 여부를 계산한다.&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        initTocTitleScroll(tocBox);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            initTocTitleScroll(tocBox);&lt;br /&gt;
        }, 120);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 우측 광고판: 이미지/번역 캡션 목록&lt;br /&gt;
var RIGHT_BILLBOARD_ITEMS = [&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
        alt: &#039;PROOF TO THE WORLD / YOU ONCE PART OF IT&#039;,&lt;br /&gt;
        duration: 3000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;당신이 한때 이 세계의&#039;,&lt;br /&gt;
            &#039;&#039;,&lt;br /&gt;
            &#039;일부였다는 것을 증명하십시오&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-003.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        file: &#039;Side-visual-002.png&#039;,&lt;br /&gt;
        alt: &#039;APPLY NOW&#039;,&lt;br /&gt;
        duration: 1000,&lt;br /&gt;
        caption: [&lt;br /&gt;
            &#039;&amp;quot;지금 지원하세요!&amp;quot;&#039;&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItem(index) {&lt;br /&gt;
    var items = RIGHT_BILLBOARD_ITEMS;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        return {&lt;br /&gt;
            file: &#039;Side-visual-001.png&#039;,&lt;br /&gt;
            alt: &#039;&#039;,&lt;br /&gt;
            caption: []&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var normalized = index % items.length;&lt;br /&gt;
    if (normalized &amp;lt; 0) normalized += items.length;&lt;br /&gt;
&lt;br /&gt;
    return items[normalized];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardImageUrl(fileName) {&lt;br /&gt;
    return &#039;/index.php?title=특수:Redirect/file/&#039; + encodeURIComponent(fileName || &#039;Side-visual-001.png&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardCaptionHtml(item) {&lt;br /&gt;
    var lines = item &amp;amp;&amp;amp; item.caption ? item.caption : [];&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    function escapeCaptionText(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/\&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lines.forEach(function(line) {&lt;br /&gt;
        var text = String(line == null ? &#039;&#039; : line);&lt;br /&gt;
        var isGap = !text.trim();&lt;br /&gt;
        var className = &#039;right-billboard-caption-line&#039; + (isGap ? &#039; is-gap&#039; : &#039;&#039;);&lt;br /&gt;
        html += &#039;&amp;lt;span class=&amp;quot;&#039; + className + &#039;&amp;quot;&amp;gt;&#039; + (isGap ? &#039;&amp;amp;nbsp;&#039; : escapeCaptionText(text)) + &#039;&amp;lt;/span&amp;gt;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return html;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setRightBillboardItem(index) {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box) return;&lt;br /&gt;
&lt;br /&gt;
    var item = getRightBillboardItem(index);&lt;br /&gt;
    var src = getRightBillboardImageUrl(item.file);&lt;br /&gt;
    var images = box.querySelectorAll(&#039;.right-billboard-image&#039;);&lt;br /&gt;
    var caption = box.querySelector(&#039;#right-billboard-caption&#039;);&lt;br /&gt;
    var emptySub = box.querySelector(&#039;.right-billboard-empty-sub&#039;);&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, String(index));&lt;br /&gt;
    box.classList.remove(&#039;is-empty&#039;);&lt;br /&gt;
&lt;br /&gt;
    Array.prototype.forEach.call(images, function(img) {&lt;br /&gt;
        img.style.display = &#039;&#039;;&lt;br /&gt;
        img.setAttribute(&#039;src&#039;, src);&lt;br /&gt;
        img.setAttribute(&#039;alt&#039;, img.classList.contains(&#039;right-billboard-image-base&#039;) ? (item.alt || &#039;&#039;) : &#039;&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (caption) {&lt;br /&gt;
        caption.innerHTML = getRightBillboardCaptionHtml(item);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (emptySub) {&lt;br /&gt;
        emptySub.textContent = item.file || &#039;Side-visual-001.png&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRightBillboardItemDuration(item) {&lt;br /&gt;
    var duration = item &amp;amp;&amp;amp; item.duration ? parseInt(item.duration, 10) : 3000;&lt;br /&gt;
&lt;br /&gt;
    if (Number.isNaN(duration) || duration &amp;lt; 500) {&lt;br /&gt;
        duration = 3000;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return duration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initRightBillboardCarousel() {&lt;br /&gt;
    var box = document.querySelector(&#039;.right-billboard-box&#039;);&lt;br /&gt;
    if (!box || box.getAttribute(&#039;data-billboard-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    box.setAttribute(&#039;data-billboard-index&#039;, &#039;0&#039;);&lt;br /&gt;
&lt;br /&gt;
    setRightBillboardItem(0);&lt;br /&gt;
&lt;br /&gt;
    if (!RIGHT_BILLBOARD_ITEMS || RIGHT_BILLBOARD_ITEMS.length &amp;lt;= 1) return;&lt;br /&gt;
&lt;br /&gt;
    function scheduleNext() {&lt;br /&gt;
        var current = parseInt(box.getAttribute(&#039;data-billboard-index&#039;) || &#039;0&#039;, 10);&lt;br /&gt;
        if (Number.isNaN(current)) current = 0;&lt;br /&gt;
&lt;br /&gt;
        var currentItem = getRightBillboardItem(current);&lt;br /&gt;
        var delay = getRightBillboardItemDuration(currentItem);&lt;br /&gt;
&lt;br /&gt;
        window.setTimeout(function() {&lt;br /&gt;
            if (!document.body.contains(box)) return;&lt;br /&gt;
&lt;br /&gt;
            if (!document.hidden) {&lt;br /&gt;
                setRightBillboardItem(current + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            scheduleNext();&lt;br /&gt;
        }, delay);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    scheduleNext();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function escapeRightBillboardAttr(value) {&lt;br /&gt;
    return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
        .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
        .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
        .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
        .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
        .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildRightBillboardBox() {&lt;br /&gt;
    var billboardInitial = getRightBillboardItem(0);&lt;br /&gt;
    var billboardSrc = getRightBillboardImageUrl(billboardInitial.file);&lt;br /&gt;
&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box right-billboard-box&amp;quot; data-billboard-index=&amp;quot;0&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title right-billboard-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;right-billboard-title-text&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-main&amp;quot;&amp;gt;Ad&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;right-billboard-title-note&amp;quot;&amp;gt;(not really)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;right-billboard-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;right-billboard-recess&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;right-billboard-screen&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img id=&amp;quot;right-billboard-image&amp;quot; class=&amp;quot;right-billboard-image right-billboard-image-base&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&#039; + escapeRightBillboardAttr(billboardInitial.alt || &#039;&#039;) + &#039;&amp;quot; onload=&amp;quot;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.remove(\&#039;is-empty\&#039;);}&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;var b=this.closest(\&#039;.right-billboard-box\&#039;); if(b){b.classList.add(\&#039;is-empty\&#039;);}&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-image-bloom&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-a&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-b&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;img class=&amp;quot;right-billboard-image right-billboard-slice right-billboard-slice-c&amp;quot; src=&amp;quot;&#039; + escapeRightBillboardAttr(billboardSrc) + &#039;&amp;quot; alt=&amp;quot;&amp;quot; aria-hidden=&amp;quot;true&amp;quot; onerror=&amp;quot;this.onerror=null;this.style.display=\&#039;none\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-glitch&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-tear&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;right-billboard-empty&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-main&amp;quot;&amp;gt;SIGNAL EMPTY&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;right-billboard-empty-sub&amp;quot;&amp;gt;&#039; + escapeRightBillboardAttr(billboardInitial.file || &#039;Side-visual-001.png&#039;) + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;right-billboard-caption&amp;quot; class=&amp;quot;right-billboard-caption&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + getRightBillboardCaptionHtml(billboardInitial) + &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buildSiteInformationBox() {&lt;br /&gt;
    return &#039;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-right-box site-info-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-title site-info-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span&amp;gt;SITE INFORMATION&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;site-info-title-meta&amp;quot;&amp;gt;LINKS&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-right-content site-info-content&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;policy-list&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/개인정보처리방침&amp;quot;&amp;gt;개인정보처리방침&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/면책_조항&amp;quot;&amp;gt;면책 조항&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/라이선스&amp;quot;&amp;gt;라이선스&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;policy-row&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/크레딧&amp;quot;&amp;gt;크레딧&amp;lt;/a&amp;gt;&amp;lt;span class=&amp;quot;policy-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;social-strip&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://discord.gg/ctaeJ9d3Q5&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;DC&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.youtube.com/@nxdsxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;YT&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://x.com/nxd_sxn&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener noreferrer&amp;quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;social-icon&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/index.php/프로젝트:소개&amp;quot;&amp;gt;WIP:&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// 초기화 함수&lt;br /&gt;
function initSidebars() {&lt;br /&gt;
    var header = $(&#039;.liberty-content-header&#039;);&lt;br /&gt;
    var content = $(&#039;.liberty-content&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (header.length &amp;amp;&amp;amp; content.length) {&lt;br /&gt;
        header.prependTo(content);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-right-sidebar&#039;).length === 0) {&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        var isLoggedIn = username !== null;&lt;br /&gt;
        var avatarSrc = isLoggedIn&lt;br /&gt;
            ? &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + username + &#039;.png&#039;&lt;br /&gt;
            : &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&#039;;&lt;br /&gt;
&lt;br /&gt;
        var userBox;&lt;br /&gt;
&lt;br /&gt;
        if (isLoggedIn) {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;/index.php?title=특수:Redirect/file/Pfp-default.png\&#039;;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;a href=&amp;quot;/index.php/사용자:&#039; + username + &#039;&amp;quot; id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;&#039; + username + &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-quick-actions&amp;quot; aria-label=&amp;quot;프로필 빠른 메뉴&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-inventory&amp;quot; aria-label=&amp;quot;인벤토리&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_PACKAGE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;인벤토리&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-achievements&amp;quot; aria-label=&amp;quot;업적&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_TROPHY + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;업적&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;profile-quick-btn&amp;quot; id=&amp;quot;profile-quick-notifications&amp;quot; aria-label=&amp;quot;알림&amp;quot;&amp;gt;&amp;lt;span id=&amp;quot;profile-quick-notification-icon&amp;quot; class=&amp;quot;profile-quick-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_BELL + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-quick-tip&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;알림&amp;lt;/span&amp;gt;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:기여/&#039; + username + &#039;&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-contribution&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_TEXT + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;기여&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:주시문서목록&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-watchlist&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SCAN_EYE + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;주시문서 목록&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php/특수:설정&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-preferences&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_SETTINGS + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;설정&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그아웃&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn clbi-user-btn-logout&amp;quot; id=&amp;quot;clbi-btn-logout&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그아웃&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            userBox =&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;clbi-right-box profile-card-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-user-avatar-wrap&amp;quot; class=&amp;quot;profile-identity-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-avatar-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;img id=&amp;quot;clbi-user-avatar&amp;quot; src=&amp;quot;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-user-name-row&amp;quot; class=&amp;quot;profile-name-row profile-name-row-guest&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-user-name&amp;quot;&amp;gt;Guest&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;clbi-right-content profile-action-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;a href=&amp;quot;/index.php?title=특수:로그인&amp;amp;returnto=대문&amp;quot; class=&amp;quot;clbi-user-btn&amp;quot; id=&amp;quot;clbi-btn-login&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-action-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_POWER + &#039;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-action-label&amp;quot;&amp;gt;로그인&amp;lt;/span&amp;gt;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid profile-action-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        var rightVisualBox = &#039;&#039;;&lt;br /&gt;
        var siteInformationBox = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            rightVisualBox = buildRightBillboardBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Right billboard build failed:&#039;, err);&lt;br /&gt;
            rightVisualBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            siteInformationBox = buildSiteInformationBox();&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            console.error(&#039;Site information build failed:&#039;, err);&lt;br /&gt;
            siteInformationBox = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        var sidebar = userBox + rightVisualBox + siteInformationBox;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).append(&#039;&amp;lt;div id=&amp;quot;clbi-right-sidebar&amp;quot;&amp;gt;&#039; + sidebar + &#039;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    if ($(&#039;#clbi-left-sidebar&#039;).length === 0) {&lt;br /&gt;
var leftSidebar =&lt;br /&gt;
    &#039;&amp;lt;div id=&amp;quot;clbi-left-sidebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;sidebar-title-svg clbi-left-language-icon&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_LANGUAGES + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-language&amp;quot;&amp;gt;언어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content sidebar-lang-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selector&amp;quot; class=&amp;quot;sidebar-lang-selector sidebar-lang-dial&amp;quot; tabindex=&amp;quot;0&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;언어 선택&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-dial-stage&amp;quot; class=&amp;quot;sidebar-lang-dial-stage&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-fan&amp;quot; class=&amp;quot;sidebar-lang-fan&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-selected-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-left&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-selected-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;한국어&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div id=&amp;quot;clbi-sidebar-lang-availability-panel&amp;quot; class=&amp;quot;sidebar-lang-status-panel sidebar-lang-status-right is-current&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span id=&amp;quot;clbi-sidebar-lang-availability-value&amp;quot; class=&amp;quot;sidebar-lang-status-value&amp;quot;&amp;gt;CURRENT&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-sidebar-lang-apply&amp;quot; class=&amp;quot;sidebar-lang-apply&amp;quot; aria-label=&amp;quot;언어 적용&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;sidebar-lang-apply-mark&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;✓&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;clbi-left-box clbi-left-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-title&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;span class=&amp;quot;news-title-icon sidebar-title-svg&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; + CLBI_SVG_NEWSPAPER + &#039;&amp;lt;/span&amp;gt; &#039; +&lt;br /&gt;
                &#039;&amp;lt;span id=&amp;quot;clbi-title-left-news&amp;quot;&amp;gt;뉴스&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;clbi-left-content clbi-news-box&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-title&amp;quot;&amp;gt;CHANGELOG&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-changelog-feed&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;a href=&amp;quot;/index.php/체인지로그&amp;quot; class=&amp;quot;news-post-item&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;news-post-title-wrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;span class=&amp;quot;news-post-title&amp;quot; id=&amp;quot;clbi-left-news-changelog-main&amp;quot;&amp;gt;체인지로그&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;i class=&amp;quot;hn hn-angle-right-solid news-post-arrow&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;span class=&amp;quot;news-post-tag&amp;quot;&amp;gt;POST&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-divider&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-feed-title&amp;quot; id=&amp;quot;clbi-left-news-recent-title&amp;quot;&amp;gt;RECENT CHANGES&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;news-left-recent-feed&amp;quot; id=&amp;quot;clbi-left-recent-list&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
    &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $(&#039;.content-wrapper&#039;).prepend(leftSidebar);&lt;br /&gt;
&lt;br /&gt;
        renderSidebarLanguageBox();&lt;br /&gt;
        loadRecentChangesList(&#039;#clbi-left-recent-list&#039;, 10);&lt;br /&gt;
        updateLeftSidebarNationsImage();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        initRightBillboardCarousel();&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        console.error(&#039;Right billboard carousel failed:&#039;, err);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    applyMainPageStyle();&lt;br /&gt;
    initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
        window.ProgressSystemWebUi.boot(&#039;initSidebars&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initNotifications();&lt;br /&gt;
            initProfile();&lt;br /&gt;
            moveTocToLeftSidebar();&lt;br /&gt;
        }, 300);&lt;br /&gt;
&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 800);&lt;br /&gt;
        setTimeout(moveTocToLeftSidebar, 1500);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    loadLangScript(function() {&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            initSidebars();&lt;br /&gt;
        }, 100);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click.profileQuickPlaceholder&#039;, &#039;#profile-quick-inventory, #profile-quick-achievements&#039;, function(e) {&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// SPA 네비게이션&lt;br /&gt;
function shouldSkip(url) {&lt;br /&gt;
    return url.match(/action=edit|action=submit|action=history|action=delete|action=protect|action=purge|특수:로그인|특수:로그아웃|Special:UserLogin|Special:UserLogout|특수:사용자정보|특수:비밀번호바꾸기|uselang=/);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function() {&lt;br /&gt;
    if (window._spaInitialized) return;&lt;br /&gt;
    window._spaInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    function isInternal(url) {&lt;br /&gt;
        var a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = url;&lt;br /&gt;
        return a.hostname === window.location.hostname;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadPage(url) {&lt;br /&gt;
        invalidateProfileRender();&lt;br /&gt;
&lt;br /&gt;
        fetch(url)&lt;br /&gt;
            .then(function(res) {&lt;br /&gt;
                return res.text();&lt;br /&gt;
            })&lt;br /&gt;
            .then(function(html) {&lt;br /&gt;
                var parser = new DOMParser();&lt;br /&gt;
                var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
                var scripts = doc.querySelectorAll(&#039;script&#039;);&lt;br /&gt;
                for (var i = 0; i &amp;lt; scripts.length; i++) {&lt;br /&gt;
                    var src = scripts[i].textContent;&lt;br /&gt;
&lt;br /&gt;
                    if (src.indexOf(&#039;wgNamespaceNumber&#039;) !== -1) {&lt;br /&gt;
                        var match = src.match(/&amp;quot;wgNamespaceNumber&amp;quot;:(-?\d+)/);&lt;br /&gt;
                        if (match) mw.config.set(&#039;wgNamespaceNumber&#039;, parseInt(match[1], 10));&lt;br /&gt;
&lt;br /&gt;
                        var matchTitle = src.match(/&amp;quot;wgTitle&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchTitle) mw.config.set(&#039;wgTitle&#039;, matchTitle[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchPage = src.match(/&amp;quot;wgPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchPage) mw.config.set(&#039;wgPageName&#039;, matchPage[1]);&lt;br /&gt;
&lt;br /&gt;
                        var matchArticle = src.match(/&amp;quot;wgArticleId&amp;quot;:(\d+)/);&lt;br /&gt;
                        if (matchArticle) {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, parseInt(matchArticle[1], 10));&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgArticleId&#039;, 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchIsMainPage = src.match(/&amp;quot;wgIsMainPage&amp;quot;:(true|false)/);&lt;br /&gt;
                        if (matchIsMainPage) {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, matchIsMainPage[1] === &#039;true&#039;);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgIsMainPage&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        var matchSpecial = src.match(/&amp;quot;wgCanonicalSpecialPageName&amp;quot;:&amp;quot;([^&amp;quot;]+)&amp;quot;/);&lt;br /&gt;
                        if (matchSpecial) {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, matchSpecial[1]);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            mw.config.set(&#039;wgCanonicalSpecialPageName&#039;, false);&lt;br /&gt;
                        }&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                var newContent = doc.querySelector(&#039;.liberty-content-main&#039;);&lt;br /&gt;
                var newTitle = doc.querySelector(&#039;.mw-page-title-main&#039;);&lt;br /&gt;
                var newHead = doc.querySelector(&#039;title&#039;);&lt;br /&gt;
                var newHeader = doc.querySelector(&#039;.liberty-content-header&#039;);&lt;br /&gt;
&lt;br /&gt;
                if (newContent) {&lt;br /&gt;
                    $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
                    $(&#039;.liberty-content-main&#039;).html(newContent.innerHTML);&lt;br /&gt;
                    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
                    $(&#039;body&#039;).removeClass(&#039;page-loading&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newTitle) {&lt;br /&gt;
                    $(&#039;.mw-page-title-main&#039;).html(newTitle.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHead) {&lt;br /&gt;
                    document.title = newHead.textContent;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (newHeader) {&lt;br /&gt;
                    $(&#039;.liberty-content-header&#039;).html(newHeader.innerHTML);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                window.scrollTo(0, 0);&lt;br /&gt;
                mw.hook(&#039;wikipage.content&#039;).fire($(&#039;.liberty-content-main&#039;));&lt;br /&gt;
                applyMainPageStyle();&lt;br /&gt;
                initCategoryNavIfAvailable(document);&lt;br /&gt;
&lt;br /&gt;
                if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.handleSpaPageView === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.handleSpaPageView();&lt;br /&gt;
                } else if (window.ProgressSystemWebUi &amp;amp;&amp;amp; typeof window.ProgressSystemWebUi.boot === &#039;function&#039;) {&lt;br /&gt;
                    window.ProgressSystemWebUi.boot(&#039;spa&#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $(&#039;#side-toc-box&#039;).remove();&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 100);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 500);&lt;br /&gt;
                setTimeout(moveTocToLeftSidebar, 1200);&lt;br /&gt;
&lt;br /&gt;
                mw.loader.using([&#039;mediawiki.api&#039;]).then(function() {&lt;br /&gt;
                    initProfile();&lt;br /&gt;
                    moveTocToLeftSidebar();&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// 목차 링크는 전용 처리&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;#side-toc-box a, #toc a, .toc a&#039;, function(e) {&lt;br /&gt;
    var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
    if (!href || href.charAt(0) !== &#039;#&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var rawId = href.slice(1);&lt;br /&gt;
    if (!rawId) return;&lt;br /&gt;
&lt;br /&gt;
    var decodedId = rawId;&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        decodedId = decodeURIComponent(rawId);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
        decodedId = rawId;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = document.getElementById(decodedId);&lt;br /&gt;
&lt;br /&gt;
    if (!target &amp;amp;&amp;amp; window.CSS &amp;amp;&amp;amp; CSS.escape) {&lt;br /&gt;
        target = document.querySelector(&#039;#&#039; + CSS.escape(decodedId));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!target) return;&lt;br /&gt;
&lt;br /&gt;
    e.preventDefault();&lt;br /&gt;
    e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    var scrollTarget = target.closest(&#039;h2, h3&#039;) || target;&lt;br /&gt;
&lt;br /&gt;
    scrollTarget.scrollIntoView({&lt;br /&gt;
        behavior: &#039;auto&#039;,&lt;br /&gt;
        block: &#039;start&#039;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    history.replaceState(null, &#039;&#039;, &#039;#&#039; + rawId);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
    $(document).on(&#039;click&#039;, &#039;a&#039;, function(e) {&lt;br /&gt;
        // 휠 클릭, 새 탭 열기, 보조키 이동은 브라우저 기본 동작을 유지한다.&lt;br /&gt;
        if (e.which &amp;amp;&amp;amp; e.which !== 1) return;&lt;br /&gt;
        if (e.button &amp;amp;&amp;amp; e.button !== 0) return;&lt;br /&gt;
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;&lt;br /&gt;
&lt;br /&gt;
        var href = $(this).attr(&#039;href&#039;);&lt;br /&gt;
        if (!href) return;&lt;br /&gt;
&lt;br /&gt;
        // 목차 링크는 별도 핸들러에서 처리&lt;br /&gt;
        if ($(this).closest(&#039;#side-toc-box, #toc, .toc&#039;).length) return;&lt;br /&gt;
&lt;br /&gt;
        // 단순 해시 링크는 SPA 가로채기 제외&lt;br /&gt;
        if (href.startsWith(&#039;#&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        var link = document.createElement(&#039;a&#039;);&lt;br /&gt;
        link.href = href;&lt;br /&gt;
&lt;br /&gt;
        var samePath = decodeURIComponent(link.pathname) === decodeURIComponent(window.location.pathname);&lt;br /&gt;
        var sameSearch = (link.search || &#039;&#039;) === (window.location.search || &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; samePath &amp;amp;&amp;amp; sameSearch) return;&lt;br /&gt;
&lt;br /&gt;
        var currentBase = window.location.href.split(&#039;#&#039;)[0];&lt;br /&gt;
        var targetBase = link.href.split(&#039;#&#039;)[0];&lt;br /&gt;
&lt;br /&gt;
        if (link.hash &amp;amp;&amp;amp; currentBase === targetBase) return;&lt;br /&gt;
&lt;br /&gt;
        if (!isInternal(href)) return;&lt;br /&gt;
        if (shouldSkip(href)) return;&lt;br /&gt;
&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        playStaticSound();&lt;br /&gt;
        $(&#039;body&#039;).addClass(&#039;page-loading&#039;);&lt;br /&gt;
        history.pushState(null, &#039;&#039;, href);&lt;br /&gt;
        loadPage(href);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    window.addEventListener(&#039;popstate&#039;, function() {&lt;br /&gt;
        loadPage(window.location.href);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// 시간 계산 함수&lt;br /&gt;
function timeAgo(timestamp) {&lt;br /&gt;
    var now = new Date();&lt;br /&gt;
    var date = new Date(timestamp);&lt;br /&gt;
    var diff = Math.floor((now - date) / 1000);&lt;br /&gt;
&lt;br /&gt;
    if (diff &amp;lt; 60) return diff + &#039;초 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 3600) return Math.floor(diff / 60) + &#039;분 전&#039;;&lt;br /&gt;
    if (diff &amp;lt; 86400) return Math.floor(diff / 3600) + &#039;시간 전&#039;;&lt;br /&gt;
    return Math.floor(diff / 86400) + &#039;일 전&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
// 펼접 토글&lt;br /&gt;
function getFoldTexts() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return (window.LANG &amp;amp;&amp;amp; window.LANG[lang])&lt;br /&gt;
        ? window.LANG[lang]&lt;br /&gt;
        : (window.LANG ? window.LANG.ko : { expand: &#039;펼치기&#039;, collapse: &#039;접기&#039; });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function refreshOpenAncestors($start) {&lt;br /&gt;
    $start.parents(&#039;[id^=&amp;quot;collapsible&amp;quot;]&#039;).each(function () {&lt;br /&gt;
        var $parent = $(this);&lt;br /&gt;
        if (!$parent.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        // 이미 fully open 상태면 굳이 다시 잠그지 않음&lt;br /&gt;
        if ($parent.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $parent.css(&#039;max-height&#039;, this.scrollHeight + &#039;px&#039;);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function bindInnerResizeUpdates($target) {&lt;br /&gt;
    // 이미지 늦게 로드될 때 높이 갱신&lt;br /&gt;
    $target.find(&#039;img&#039;).off(&#039;.foldimg&#039;).on(&#039;load.foldimg&#039;, function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
            if ($target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
                $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            }&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;opening&#039;);&lt;br /&gt;
    $target.addClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    // 열린 뒤 자연 확장 가능하게 만들기 위해 먼저 px로 열기&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.collapse);&lt;br /&gt;
&lt;br /&gt;
    bindInnerResizeUpdates($target);&lt;br /&gt;
&lt;br /&gt;
    // 바깥 펼접 즉시 갱신&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    // 전환 끝나면 none으로 풀어서 중첩 펼접/동적 내용 증가를 자연스럽게 허용&lt;br /&gt;
    $target.off(&#039;transitionend.foldopen&#039;).on(&#039;transitionend.foldopen&#039;, function (e) {&lt;br /&gt;
        if (e.target !== this) return;&lt;br /&gt;
        if (!$target.hasClass(&#039;folding-open&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
        $target.css(&#039;max-height&#039;, &#039;none&#039;);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;open&#039;);&lt;br /&gt;
&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // 늦게 렌더되는 콘텐츠 대응&lt;br /&gt;
    requestAnimationFrame(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 80);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        if ($target.hasClass(&#039;folding-open&#039;) &amp;amp;&amp;amp; $target.data(&#039;fold-state&#039;) !== &#039;open&#039;) {&lt;br /&gt;
            $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
            refreshOpenAncestors($target);&lt;br /&gt;
        }&lt;br /&gt;
    }, 220);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function closeFold($target, $btn) {&lt;br /&gt;
    var t = getFoldTexts();&lt;br /&gt;
&lt;br /&gt;
    // none 상태에서 닫으면 transition이 안 되므로 실제 높이로 고정&lt;br /&gt;
    if ($target.css(&#039;max-height&#039;) === &#039;none&#039; || $target.data(&#039;fold-state&#039;) === &#039;open&#039;) {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
        $target.css(&#039;max-height&#039;, $target[0].scrollHeight + &#039;px&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $target.data(&#039;fold-state&#039;, &#039;closing&#039;);&lt;br /&gt;
    $target[0].offsetHeight;&lt;br /&gt;
    $target.css(&#039;max-height&#039;, &#039;0px&#039;);&lt;br /&gt;
    $target.removeClass(&#039;folding-open&#039;);&lt;br /&gt;
&lt;br /&gt;
    $btn.text(t.expand);&lt;br /&gt;
&lt;br /&gt;
    refreshOpenAncestors($target);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
        refreshOpenAncestors($target);&lt;br /&gt;
        $target.data(&#039;fold-state&#039;, &#039;closed&#039;);&lt;br /&gt;
    }, 250);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiToggle&#039;, &#039;.toggleBtn&#039;, function () {&lt;br /&gt;
            var $btn = $(this);&lt;br /&gt;
            var targetId = $btn.data(&#039;target&#039;);&lt;br /&gt;
            var $target = $(&#039;#&#039; + targetId);&lt;br /&gt;
            if (!$target.length) return;&lt;br /&gt;
&lt;br /&gt;
            var scrollY = window.scrollY;&lt;br /&gt;
&lt;br /&gt;
            if ($target.hasClass(&#039;folding-open&#039;)) {&lt;br /&gt;
                closeFold($target, $btn);&lt;br /&gt;
            } else {&lt;br /&gt;
                openFold($target, $btn);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            window.scrollTo(0, scrollY);&lt;br /&gt;
        });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// ========== 프로필 시스템 ==========&lt;br /&gt;
function initProfile() {&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    $(&#039;.user-profile-portal&#039;).removeClass(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var token = ++PROFILE_RENDER_TOKEN;&lt;br /&gt;
    var ns = mw.config.get(&#039;wgNamespaceNumber&#039;);&lt;br /&gt;
    var title = mw.config.get(&#039;wgTitle&#039;);&lt;br /&gt;
    var specialPage = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
    var isProfileSettings = specialPage === &#039;사용자정보&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-page&#039;, ns === 2);&lt;br /&gt;
    $(&#039;body&#039;).toggleClass(&#039;user-profile-settings-page&#039;, isProfileSettings);&lt;br /&gt;
&lt;br /&gt;
    if (ns === 2) {&lt;br /&gt;
        var profileUser = title.split(&#039;/&#039;)[0];&lt;br /&gt;
        renderProfile(profileUser, token);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isProfileSettings) {&lt;br /&gt;
        initUserProfilePage();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderProfile(username, token) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;query&#039;,&lt;br /&gt;
        list: &#039;users&#039;,&lt;br /&gt;
        ususers: username,&lt;br /&gt;
        usprop: &#039;editcount&#039;&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        if (token !== PROFILE_RENDER_TOKEN) return;&lt;br /&gt;
        if (mw.config.get(&#039;wgNamespaceNumber&#039;) !== 2) return;&lt;br /&gt;
&lt;br /&gt;
        var currentTitle = String(mw.config.get(&#039;wgTitle&#039;) || &#039;&#039;).split(&#039;/&#039;)[0];&lt;br /&gt;
        if (currentTitle !== username) return;&lt;br /&gt;
&lt;br /&gt;
        var user = data.query.users[0];&lt;br /&gt;
        var contentEl = document.getElementById(&#039;mw-content-text&#039;);&lt;br /&gt;
        if (!contentEl) return;&lt;br /&gt;
&lt;br /&gt;
        var pageContent = contentEl.querySelector(&#039;.mw-parser-output&#039;) || contentEl;&lt;br /&gt;
        injectProfileCard(username, user, pageContent);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectProfileCard(username, userData, container) {&lt;br /&gt;
    var isOwnPage = mw.config.get(&#039;wgUserName&#039;) === username;&lt;br /&gt;
    var editCount = (userData &amp;amp;&amp;amp; userData.editcount) ? userData.editcount : 0;&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(value) {&lt;br /&gt;
        return String(value == null ? &#039;&#039; : value)&lt;br /&gt;
            .replace(/&amp;amp;/g, &#039;&amp;amp;amp;&#039;)&lt;br /&gt;
            .replace(/&amp;lt;/g, &#039;&amp;amp;lt;&#039;)&lt;br /&gt;
            .replace(/&amp;gt;/g, &#039;&amp;amp;gt;&#039;)&lt;br /&gt;
            .replace(/&amp;quot;/g, &#039;&amp;amp;quot;&#039;)&lt;br /&gt;
            .replace(/&#039;/g, &#039;&amp;amp;#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    container.classList.add(&#039;user-profile-portal&#039;);&lt;br /&gt;
&lt;br /&gt;
    var safeUsername = escapeHtml(username);&lt;br /&gt;
    var avatarSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-&#039; + encodeURIComponent(username) + &#039;.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var fallbackSrc = &#039;/index.php?title=특수:Redirect/file/Pfp-default.png&amp;amp;width=220&#039;;&lt;br /&gt;
    var editBtn = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;a href=&amp;quot;/index.php/특수:사용자정보&amp;quot; class=&amp;quot;profile-edit-btn&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-label&amp;quot;&amp;gt;프로필 수정&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;profile-edit-arrow&amp;quot;&amp;gt;›&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var progressHtml = isOwnPage&lt;br /&gt;
        ? &#039;&amp;lt;div class=&amp;quot;profile-page-progress is-syncing&amp;quot; data-profile-progress&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;LEVEL RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-page-progress-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-level&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;profile-page-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;profile-page-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-sub&amp;quot;&amp;gt;SYNCING&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-page-progress-meta&amp;quot;&amp;gt;TODAY — · DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;&lt;br /&gt;
        : &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    var card = document.createElement(&#039;div&#039;);&lt;br /&gt;
    card.className = &#039;profile-card profile-page-console&#039;;&lt;br /&gt;
    card.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-titlebar&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;USER PROFILE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;OFFICIAL ARCHIVE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div class=&amp;quot;profile-card-body&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-identity-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-avatar-bay&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img src=&amp;quot;&#039; + avatarSrc + &#039;&amp;quot; onerror=&amp;quot;this.onerror=null;this.src=\&#039;&#039; + fallbackSrc + &#039;\&#039;;&amp;quot; alt=&amp;quot;&#039; + safeUsername + &#039;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-info-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-nameplate&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;h2 class=&amp;quot;profile-username&amp;quot;&amp;gt;&#039; + safeUsername + &#039;&amp;lt;/h2&amp;gt;&#039; +&lt;br /&gt;
                        editBtn +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-name&amp;quot; data-field=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-role&amp;quot; data-field=&amp;quot;role&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-discord&amp;quot; data-field=&amp;quot;discord&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;profile-lower-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-bio-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;BIOGRAPHY&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-bio&amp;quot; data-field=&amp;quot;bio&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;profile-stats-panel&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-section-title&amp;quot;&amp;gt;RECORD&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;profile-stats&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                        progressHtml +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-stat-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot;&amp;gt;&#039; + editCount + &#039;&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;수정 횟수&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-stat&amp;quot; data-contrib-pages-stat&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-value&amp;quot; data-contrib-pages-value&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;clbi-stat-label&amp;quot;&amp;gt;기여 문서&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;div class=&amp;quot;profile-info-grid&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;TIME&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-time&amp;gt;UTC --:--&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;div class=&amp;quot;profile-info-stat&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-label&amp;quot;&amp;gt;LANGUAGE&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                                &#039;&amp;lt;span class=&amp;quot;profile-info-value&amp;quot; data-profile-language&amp;gt;—&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.profile-card&#039;).remove();&lt;br /&gt;
    container.insertBefore(card, container.firstChild);&lt;br /&gt;
    loadProfileFields(username, card);&lt;br /&gt;
    loadProfileContributionPages(username, card);&lt;br /&gt;
    updateProfilePageEnvironment(card, null);&lt;br /&gt;
&lt;br /&gt;
    if (isOwnPage) {&lt;br /&gt;
        loadProfileProgressForUserPage(card);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getProfileLanguageLabel() {&lt;br /&gt;
    var lang = getCurrentLang();&lt;br /&gt;
    return SIDEBAR_LANGUAGE_LABELS[lang] || (lang ? lang.toUpperCase() : &#039;—&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfilePageEnvironment(card, summary) {&lt;br /&gt;
    if (!card) return;&lt;br /&gt;
&lt;br /&gt;
    var timezone = summary &amp;amp;&amp;amp; summary.timezone ? summary.timezone : &#039;UTC&#039;;&lt;br /&gt;
    var timeEl = card.querySelector(&#039;[data-profile-time]&#039;);&lt;br /&gt;
    var langEl = card.querySelector(&#039;[data-profile-language]&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (timeEl) {&lt;br /&gt;
        try {&lt;br /&gt;
            timeEl.textContent = timezone + &#039; &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: timezone&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        } catch (err) {&lt;br /&gt;
            timeEl.textContent = &#039;UTC &#039; + new Intl.DateTimeFormat(&#039;ko-KR&#039;, {&lt;br /&gt;
                hour: &#039;2-digit&#039;,&lt;br /&gt;
                minute: &#039;2-digit&#039;,&lt;br /&gt;
                hour12: false,&lt;br /&gt;
                timeZone: &#039;UTC&#039;&lt;br /&gt;
            }).format(new Date());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (langEl) {&lt;br /&gt;
        langEl.textContent = getProfileLanguageLabel();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileContributionPages(username, card) {&lt;br /&gt;
    if (!username || !card) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    var valueEl = card.querySelector(&#039;[data-contrib-pages-value]&#039;);&lt;br /&gt;
    if (valueEl) valueEl.textContent = &#039;SYNC&#039;;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        var pages = Object.create(null);&lt;br /&gt;
        var cont = {};&lt;br /&gt;
        var guard = 0;&lt;br /&gt;
&lt;br /&gt;
        function requestNext() {&lt;br /&gt;
            guard++;&lt;br /&gt;
&lt;br /&gt;
            var params = Object.assign({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                list: &#039;usercontribs&#039;,&lt;br /&gt;
                ucuser: username,&lt;br /&gt;
                ucnamespace: 0,&lt;br /&gt;
                ucprop: &#039;title&#039;,&lt;br /&gt;
                uclimit: &#039;max&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }, cont);&lt;br /&gt;
&lt;br /&gt;
            return api.get(params).then(function (data) {&lt;br /&gt;
                var rows = data &amp;amp;&amp;amp; data.query &amp;amp;&amp;amp; data.query.usercontribs ? data.query.usercontribs : [];&lt;br /&gt;
&lt;br /&gt;
                rows.forEach(function (row) {&lt;br /&gt;
                    if (row &amp;amp;&amp;amp; row.title) pages[row.title] = true;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                if (data &amp;amp;&amp;amp; data.continue &amp;amp;&amp;amp; data.continue.uccontinue &amp;amp;&amp;amp; guard &amp;lt; 40) {&lt;br /&gt;
                    cont = data.continue;&lt;br /&gt;
                    return requestNext();&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (valueEl) valueEl.textContent = Object.keys(pages).length;&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        requestNext().fail(function () {&lt;br /&gt;
            if (valueEl) valueEl.textContent = &#039;—&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileProgressForUserPage(card) {&lt;br /&gt;
    if (!mw.config.get(&#039;wgUserName&#039;)) return;&lt;br /&gt;
    if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) return;&lt;br /&gt;
&lt;br /&gt;
    mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
        var api = new mw.Api();&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;progress_summary&#039;,&lt;br /&gt;
            format: &#039;json&#039;,&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (data) {&lt;br /&gt;
            var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
            if (!payload || !payload.available || !payload.summary) return;&lt;br /&gt;
            updateUserPageProgress(card, payload.summary);&lt;br /&gt;
            updateProfilePageEnvironment(card, payload.summary);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateUserPageProgress(card, summary) {&lt;br /&gt;
    var panel = card.querySelector(&#039;[data-profile-progress]&#039;);&lt;br /&gt;
    if (!panel || !summary) return;&lt;br /&gt;
&lt;br /&gt;
    var level = summary.level || 1;&lt;br /&gt;
    var totalXp = summary.totalXp || 0;&lt;br /&gt;
    var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
    var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
    var percent = Math.max(0, Math.min(100, summary.progressPercent || 0));&lt;br /&gt;
    var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
    var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
    var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
&lt;br /&gt;
    panel.classList.remove(&#039;is-syncing&#039;);&lt;br /&gt;
    panel.classList.toggle(&#039;is-max-level&#039;, isMaxLevel);&lt;br /&gt;
&lt;br /&gt;
    var levelEl = panel.querySelector(&#039;.profile-page-level&#039;);&lt;br /&gt;
    var totalEl = panel.querySelector(&#039;.profile-page-total-xp&#039;);&lt;br /&gt;
    var fillEl = panel.querySelector(&#039;.profile-page-xp-fill&#039;);&lt;br /&gt;
    var subEl = panel.querySelector(&#039;.profile-page-progress-sub&#039;);&lt;br /&gt;
    var metaEl = panel.querySelector(&#039;.profile-page-progress-meta&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (levelEl) levelEl.textContent = (isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level;&lt;br /&gt;
    if (totalEl) totalEl.textContent = totalXp + &#039; XP&#039;;&lt;br /&gt;
    if (fillEl) fillEl.style.width = percent + &#039;%&#039;;&lt;br /&gt;
    if (subEl) subEl.textContent = isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;);&lt;br /&gt;
    if (metaEl) metaEl.textContent = &#039;TODAY &#039; + dailyXp + &#039; XP · DISCOVERED &#039; + discoveries;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadProfileFields(username, card) {&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    api.get({&lt;br /&gt;
        action: &#039;userprofile&#039;,&lt;br /&gt;
        user: username&lt;br /&gt;
    }).then(function(data) {&lt;br /&gt;
        var profile = data.userprofile;&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: profile.name || &#039;&#039;,&lt;br /&gt;
            discord: profile.discord || &#039;&#039;,&lt;br /&gt;
            role: profile.role || &#039;&#039;,&lt;br /&gt;
            bio: profile.bio || &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    }).fail(function() {&lt;br /&gt;
        updateProfileFields(card, {&lt;br /&gt;
            name: &#039;&#039;,&lt;br /&gt;
            discord: &#039;&#039;,&lt;br /&gt;
            role: &#039;&#039;,&lt;br /&gt;
            bio: &#039;&#039;&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateProfileFields(card, data) {&lt;br /&gt;
    var nameEl = card.querySelector(&#039;[data-field=&amp;quot;name&amp;quot;]&#039;);&lt;br /&gt;
    var roleEl = card.querySelector(&#039;[data-field=&amp;quot;role&amp;quot;]&#039;);&lt;br /&gt;
    var discordEl = card.querySelector(&#039;[data-field=&amp;quot;discord&amp;quot;]&#039;);&lt;br /&gt;
    var bioEl = card.querySelector(&#039;[data-field=&amp;quot;bio&amp;quot;]&#039;);&lt;br /&gt;
    if (nameEl) nameEl.textContent = data.name || &#039;&#039;;&lt;br /&gt;
    if (roleEl) roleEl.textContent = data.role || &#039;&#039;;&lt;br /&gt;
    if (discordEl) discordEl.textContent = data.discord ? (&#039;디스코드: &#039; + data.discord) : &#039;&#039;;&lt;br /&gt;
    if (bioEl) bioEl.textContent = data.bio || &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
// ========== 프로필 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
// ========== 알림 시스템 ==========&lt;br /&gt;
function ensureNotificationPopup() {&lt;br /&gt;
    if (document.getElementById(&#039;clbi-notification-popup&#039;)) return;&lt;br /&gt;
&lt;br /&gt;
    var popup = document.createElement(&#039;div&#039;);&lt;br /&gt;
    popup.id = &#039;clbi-notification-popup&#039;;&lt;br /&gt;
    popup.style.cssText =&lt;br /&gt;
        &#039;display:none;position:fixed;z-index:99999;width:320px;max-height:420px;&#039; +&lt;br /&gt;
        &#039;background:#0a0909;border:2px solid #854369;border-radius:5px;&#039; +&lt;br /&gt;
        &#039;box-shadow:0 0 0 1px #1a1a1a, 0 8px 24px rgba(0,0,0,0.55);overflow:hidden;&#039;;&lt;br /&gt;
&lt;br /&gt;
    popup.innerHTML =&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:10px 12px;border-bottom:2px solid #854369;background:linear-gradient(to bottom, #171114 0%, #0a0909 100%);color:#E2E2E2;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span&amp;gt;알림&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-notification-readall&amp;quot; style=&amp;quot;background:#171717;border:1px solid #854369;border-radius:6px;color:#E2E2E2;font-size:11px;font-weight:700;padding:4px 8px;cursor:pointer;&amp;quot;&amp;gt;전체 읽음&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div id=&amp;quot;clbi-notification-list&amp;quot; style=&amp;quot;max-height:320px;overflow-y:auto;padding:8px 0;color:#E2E2E2;font-size:12px;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;div style=&amp;quot;padding:8px;border-top:1px solid #2a2a2a;background:#111;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;/index.php?title=Special:Notifications&amp;quot; id=&amp;quot;clbi-notification-more&amp;quot; style=&amp;quot;display:block;width:100%;text-align:center;padding:8px 10px;border-radius:6px;background:#171717;border:1px solid #854369;color:#E2E2E2 !important;text-decoration:none !important;font-size:12px;font-weight:700;&amp;quot;&amp;gt;더보기&amp;lt;/a&amp;gt;&#039; +&lt;br /&gt;
        &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
    document.body.appendChild(popup);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function positionNotificationPopup() {&lt;br /&gt;
    var btn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
    var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
    if (!btn || !popup) return;&lt;br /&gt;
&lt;br /&gt;
    var rect = btn.getBoundingClientRect();&lt;br /&gt;
    var top = rect.bottom + 6;&lt;br /&gt;
    var left = rect.left + (rect.width / 2) - (popup.offsetWidth / 2);&lt;br /&gt;
&lt;br /&gt;
    if (left &amp;lt; 8) left = 8;&lt;br /&gt;
    if (left + popup.offsetWidth &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
        left = window.innerWidth - popup.offsetWidth - 8;&lt;br /&gt;
    }&lt;br /&gt;
    if (top + popup.offsetHeight &amp;gt; window.innerHeight - 8) {&lt;br /&gt;
        top = Math.max(8, rect.top - popup.offsetHeight - 6);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    popup.style.top = top + &#039;px&#039;;&lt;br /&gt;
    popup.style.left = left + &#039;px&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseNotificationItemsFromHtml(html) {&lt;br /&gt;
    var parser = new DOMParser();&lt;br /&gt;
    var doc = parser.parseFromString(html, &#039;text/html&#039;);&lt;br /&gt;
&lt;br /&gt;
    var selectors = [&lt;br /&gt;
        &#039;.mw-echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;.mw-echo-ui-notificationsInboxWidgetRow&#039;,&lt;br /&gt;
        &#039;.echo-ui-notificationItemWidget&#039;,&lt;br /&gt;
        &#039;li[data-notification-id]&#039;,&lt;br /&gt;
        &#039;.mw-echo-notifications-list li&#039;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
    var items = [];&lt;br /&gt;
    for (var i = 0; i &amp;lt; selectors.length; i++) {&lt;br /&gt;
        items = Array.prototype.slice.call(doc.querySelectorAll(selectors[i]));&lt;br /&gt;
        if (items.length) break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return items.slice(0, 5).map(function(item) {&lt;br /&gt;
        var link = item.querySelector(&#039;a[href]&#039;);&lt;br /&gt;
        var href = link ? link.getAttribute(&#039;href&#039;) : &#039;/index.php?title=Special:Notifications&#039;;&lt;br /&gt;
        var text = (item.textContent || &#039;&#039;).replace(/\s+/g, &#039; &#039;).trim();&lt;br /&gt;
&lt;br /&gt;
        var notificationId =&lt;br /&gt;
            item.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
            item.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
            &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (!notificationId) {&lt;br /&gt;
            var anyWithId = item.querySelector(&#039;[data-notification-id], [data-id], [data-notification]&#039;);&lt;br /&gt;
            if (anyWithId) {&lt;br /&gt;
                notificationId =&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-id&#039;) ||&lt;br /&gt;
                    anyWithId.getAttribute(&#039;data-notification&#039;) ||&lt;br /&gt;
                    &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (href &amp;amp;&amp;amp; href.indexOf(&#039;http&#039;) !== 0) {&lt;br /&gt;
            href = href.charAt(0) === &#039;/&#039;&lt;br /&gt;
                ? href&lt;br /&gt;
                : &#039;/index.php&#039; + (href.charAt(0) === &#039;?&#039; ? href : &#039;/&#039; + href);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            id: notificationId,&lt;br /&gt;
            href: href,&lt;br /&gt;
            text: text || &#039;알림&#039;&lt;br /&gt;
        };&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setNotificationIcon(hasItems) {&lt;br /&gt;
    var quickIcon = document.getElementById(&#039;profile-quick-notification-icon&#039;);&lt;br /&gt;
    var svg = hasItems ? CLBI_SVG_BELL_DOT : CLBI_SVG_BELL;&lt;br /&gt;
&lt;br /&gt;
    if (quickIcon) {&lt;br /&gt;
        quickIcon.innerHTML = svg;&lt;br /&gt;
        quickIcon.classList.toggle(&#039;has-notifications&#039;, !!hasItems);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function renderNotificationPopup(items) {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    var badge = document.getElementById(&#039;clbi-notification-badge&#039;);&lt;br /&gt;
    if (!list) return;&lt;br /&gt;
&lt;br /&gt;
    if (!items || !items.length) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;표시할 알림이 없습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
        if (badge) badge.style.display = &#039;none&#039;;&lt;br /&gt;
        setNotificationIcon(false);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var html = &#039;&#039;;&lt;br /&gt;
    for (var i = 0; i &amp;lt; items.length; i++) {&lt;br /&gt;
        html +=&lt;br /&gt;
            &#039;&amp;lt;a href=&amp;quot;&#039; + items[i].href + &#039;&amp;quot; class=&amp;quot;clbi-notification-item&amp;quot; data-notification-id=&amp;quot;&#039; + (items[i].id || &#039;&#039;) + &#039;&amp;quot; style=&amp;quot;display:block;padding:10px 12px;color:#E2E2E2 !important;text-decoration:none !important;border-bottom:1px solid #1f1f1f;line-height:1.5;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                items[i].text +&lt;br /&gt;
            &#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    list.innerHTML = html;&lt;br /&gt;
&lt;br /&gt;
    if (badge) {&lt;br /&gt;
        badge.textContent = items.length;&lt;br /&gt;
        badge.style.display = &#039;block&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    setNotificationIcon(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadNotificationsIntoPopup() {&lt;br /&gt;
    var list = document.getElementById(&#039;clbi-notification-list&#039;);&lt;br /&gt;
    if (list) {&lt;br /&gt;
        list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;불러오는 중...&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fetch(&#039;/index.php?title=Special:Notifications&#039;, { credentials: &#039;same-origin&#039; })&lt;br /&gt;
        .then(function(res) {&lt;br /&gt;
            return res.text();&lt;br /&gt;
        })&lt;br /&gt;
        .then(function(html) {&lt;br /&gt;
            var items = parseNotificationItemsFromHtml(html);&lt;br /&gt;
            renderNotificationPopup(items);&lt;br /&gt;
        })&lt;br /&gt;
        .catch(function(err) {&lt;br /&gt;
            console.error(err);&lt;br /&gt;
            if (list) {&lt;br /&gt;
                list.innerHTML = &#039;&amp;lt;div style=&amp;quot;padding:14px 12px;color:#999;&amp;quot;&amp;gt;알림을 불러오지 못했습니다.&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markAllNotificationsRead() {&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: &#039;all&#039;&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function markNotificationReadById(notificationId) {&lt;br /&gt;
    if (!notificationId) {&lt;br /&gt;
        return $.Deferred().resolve().promise();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return new mw.Api().postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
        action: &#039;echomarkread&#039;,&lt;br /&gt;
        list: notificationId&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initNotifications() {&lt;br /&gt;
    var quickBtn = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!quickBtn) return;&lt;br /&gt;
&lt;br /&gt;
    ensureNotificationPopup();&lt;br /&gt;
    loadNotificationsIntoPopup();&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationToggle&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationToggle&#039;, &#039;#profile-quick-notifications&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (popup.style.display === &#039;none&#039; || popup.style.display === &#039;&#039;) {&lt;br /&gt;
                popup.style.display = &#039;block&#039;;&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
            } else {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationOutside&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationOutside&#039;, function(e) {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            var quickToggle = document.getElementById(&#039;profile-quick-notifications&#039;);&lt;br /&gt;
            if (!popup) return;&lt;br /&gt;
&lt;br /&gt;
            if (!popup.contains(e.target) &amp;amp;&amp;amp; (!quickToggle || !quickToggle.contains(e.target))) {&lt;br /&gt;
                popup.style.display = &#039;none&#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationReadAll&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationReadAll&#039;, &#039;#clbi-notification-readall&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var button = this;&lt;br /&gt;
            button.disabled = true;&lt;br /&gt;
            button.textContent = &#039;처리 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            markAllNotificationsRead()&lt;br /&gt;
                .then(function() {&lt;br /&gt;
                    loadNotificationsIntoPopup();&lt;br /&gt;
                })&lt;br /&gt;
                .always(function() {&lt;br /&gt;
                    button.disabled = false;&lt;br /&gt;
                    button.textContent = &#039;전체 읽음&#039;;&lt;br /&gt;
                });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(document)&lt;br /&gt;
        .off(&#039;click.clbiNotificationItem&#039;)&lt;br /&gt;
        .on(&#039;click.clbiNotificationItem&#039;, &#039;.clbi-notification-item&#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
            var href = this.getAttribute(&#039;href&#039;);&lt;br /&gt;
            var notificationId = this.getAttribute(&#039;data-notification-id&#039;) || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            markNotificationReadById(notificationId).always(function() {&lt;br /&gt;
                loadNotificationsIntoPopup();&lt;br /&gt;
                if (href) {&lt;br /&gt;
                    window.location.href = href;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(window)&lt;br /&gt;
        .off(&#039;resize.clbiNotification&#039;)&lt;br /&gt;
        .on(&#039;resize.clbiNotification&#039;, function() {&lt;br /&gt;
            var popup = document.getElementById(&#039;clbi-notification-popup&#039;);&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; popup.style.display === &#039;block&#039;) {&lt;br /&gt;
                positionNotificationPopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
}&lt;br /&gt;
// ========== 알림 시스템 끝 ==========&lt;br /&gt;
&lt;br /&gt;
function initUserProfilePage() {&lt;br /&gt;
    $(&#039;body&#039;).addClass(&#039;user-profile-settings-page&#039;);&lt;br /&gt;
&lt;br /&gt;
    var saveBtn = document.getElementById(&#039;pref-save&#039;);&lt;br /&gt;
    if (!saveBtn) return;&lt;br /&gt;
&lt;br /&gt;
    function getPrefRow(id) {&lt;br /&gt;
        var el = document.getElementById(id);&lt;br /&gt;
        if (!el) return null;&lt;br /&gt;
        return el.closest(&#039;.clbi-pref-row&#039;) || el.parentNode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removePrefRow(id) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (row &amp;amp;&amp;amp; row.parentNode) {&lt;br /&gt;
            row.parentNode.removeChild(row);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function createPrefSection(className, titleText) {&lt;br /&gt;
        var section = document.createElement(&#039;div&#039;);&lt;br /&gt;
        section.className = &#039;clbi-pref-section &#039; + className;&lt;br /&gt;
&lt;br /&gt;
        var title = document.createElement(&#039;div&#039;);&lt;br /&gt;
        title.className = &#039;clbi-pref-section-title&#039;;&lt;br /&gt;
        title.textContent = titleText;&lt;br /&gt;
&lt;br /&gt;
        var body = document.createElement(&#039;div&#039;);&lt;br /&gt;
        body.className = &#039;clbi-pref-section-body&#039;;&lt;br /&gt;
&lt;br /&gt;
        section.appendChild(title);&lt;br /&gt;
        section.appendChild(body);&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            section: section,&lt;br /&gt;
            body: body&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function moveRowToSection(id, targetBody, className) {&lt;br /&gt;
        var row = getPrefRow(id);&lt;br /&gt;
        if (!row || !targetBody) return false;&lt;br /&gt;
&lt;br /&gt;
        row.classList.add(&#039;clbi-pref-row-key-&#039; + className);&lt;br /&gt;
        targetBody.appendChild(row);&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function rebuildProfileSettingsLayout() {&lt;br /&gt;
        var root = document.querySelector(&#039;.clbi-prefs-profile&#039;);&lt;br /&gt;
        if (!root || root.dataset.profileSettingsReworked === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        root.dataset.profileSettingsReworked = &#039;1&#039;;&lt;br /&gt;
        root.classList.add(&#039;profile-settings-console&#039;);&lt;br /&gt;
&lt;br /&gt;
        removePrefRow(&#039;pref-badges&#039;);&lt;br /&gt;
&lt;br /&gt;
        var originalRows = Array.prototype.slice.call(root.querySelectorAll(&#039;.clbi-pref-row&#039;));&lt;br /&gt;
        var actionNodes = [];&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn.parentNode === root || saveBtn.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(saveBtn);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var statusNode = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        if (statusNode &amp;amp;&amp;amp; statusNode.closest(&#039;.clbi-prefs-profile&#039;) === root) {&lt;br /&gt;
            actionNodes.push(statusNode);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var main = document.createElement(&#039;div&#039;);&lt;br /&gt;
        main.className = &#039;clbi-pref-main-grid&#039;;&lt;br /&gt;
&lt;br /&gt;
        var media = createPrefSection(&#039;clbi-pref-section-media&#039;, &#039;PROFILE IMAGE&#039;);&lt;br /&gt;
        var identity = createPrefSection(&#039;clbi-pref-section-identity&#039;, &#039;IDENTITY RECORD&#039;);&lt;br /&gt;
        var bio = createPrefSection(&#039;clbi-pref-section-bio&#039;, &#039;BIOGRAPHY&#039;);&lt;br /&gt;
        var account = createPrefSection(&#039;clbi-pref-section-account&#039;, &#039;ACCOUNT CONTACT&#039;);&lt;br /&gt;
        var misc = createPrefSection(&#039;clbi-pref-section-misc&#039;, &#039;OTHER OPTIONS&#039;);&lt;br /&gt;
&lt;br /&gt;
        main.appendChild(media.section);&lt;br /&gt;
        main.appendChild(identity.section);&lt;br /&gt;
        main.appendChild(bio.section);&lt;br /&gt;
        main.appendChild(account.section);&lt;br /&gt;
        main.appendChild(misc.section);&lt;br /&gt;
&lt;br /&gt;
        root.innerHTML = &#039;&#039;;&lt;br /&gt;
        root.appendChild(main);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-preview&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-btn&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-pfp-input&#039;, media.body, &#039;pfp&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-name&#039;, identity.body, &#039;name&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-role&#039;, identity.body, &#039;role&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-discord&#039;, identity.body, &#039;discord&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-bio&#039;, bio.body, &#039;bio&#039;);&lt;br /&gt;
&lt;br /&gt;
        moveRowToSection(&#039;pref-new-email&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-password&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
        moveRowToSection(&#039;pref-email-save&#039;, account.body, &#039;email&#039;);&lt;br /&gt;
&lt;br /&gt;
        originalRows.forEach(function (row) {&lt;br /&gt;
            if (!row.parentNode &amp;amp;&amp;amp; !row.className.match(/clbi-pref-row-key-/)) {&lt;br /&gt;
                misc.body.appendChild(row);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!misc.body.children.length) {&lt;br /&gt;
            misc.section.parentNode.removeChild(misc.section);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var actions = document.createElement(&#039;div&#039;);&lt;br /&gt;
        actions.className = &#039;clbi-pref-actions&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (saveBtn) actions.appendChild(saveBtn);&lt;br /&gt;
        if (statusNode) actions.appendChild(statusNode);&lt;br /&gt;
&lt;br /&gt;
        root.appendChild(actions);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rebuildProfileSettingsLayout();&lt;br /&gt;
&lt;br /&gt;
    var api = new mw.Api();&lt;br /&gt;
    var selectedFile = null;&lt;br /&gt;
    var cropper = null;&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-gallery-modal&#039;)) {&lt;br /&gt;
        var gModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        gModal.id = &#039;clbi-gallery-modal&#039;;&lt;br /&gt;
        gModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        gModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:480px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;justify-content:space-between;align-items:center;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;프로필 사진 선택&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-close&amp;quot; style=&amp;quot;background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;&amp;quot;&amp;gt;✕&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-gallery-upload-btn&amp;quot; style=&amp;quot;background:#2a2a2a;border:2px dashed #854369;border-radius:8px;padding:32px;color:#e2e2e2;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:13px;width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;font-size:32px;&amp;quot;&amp;gt;🖼️&amp;lt;/span&amp;gt;새 사진 업로드&#039; +&lt;br /&gt;
                &#039;&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history-section&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div style=&amp;quot;font-size:11px;color:#888;margin-bottom:8px;&amp;quot;&amp;gt;이전 사진 — 클릭하면 바로 적용&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div id=&amp;quot;clbi-gallery-history&amp;quot; style=&amp;quot;display:flex;gap:8px;flex-wrap:wrap;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(gModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.getElementById(&#039;clbi-crop-modal&#039;)) {&lt;br /&gt;
        var cModal = document.createElement(&#039;div&#039;);&lt;br /&gt;
        cModal.id = &#039;clbi-crop-modal&#039;;&lt;br /&gt;
        cModal.style.cssText =&lt;br /&gt;
            &#039;display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;align-items:center;justify-content:center;&#039;;&lt;br /&gt;
&lt;br /&gt;
        cModal.innerHTML =&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;background:#1e1e1e;border:2px solid #854369;border-radius:12px;padding:24px;max-width:500px;width:90%;display:flex;flex-direction:column;gap:16px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;font-size:14px;font-weight:700;color:#e2e2e2;&amp;quot;&amp;gt;사진 조정&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%;max-height:380px;overflow:hidden;border-radius:8px;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;img id=&amp;quot;clbi-crop-image&amp;quot; style=&amp;quot;max-width:100%;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;display:flex;gap:8px;justify-content:flex-end;&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-cancel&amp;quot; style=&amp;quot;background:#2a2a2a;color:#e2e2e2;border:1px solid #444;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;취소&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;button type=&amp;quot;button&amp;quot; id=&amp;quot;clbi-crop-confirm&amp;quot; style=&amp;quot;background:#854369;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;&amp;quot;&amp;gt;확정&amp;lt;/button&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
        document.body.appendChild(cModal);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gModal = document.getElementById(&#039;clbi-gallery-modal&#039;);&lt;br /&gt;
    var cModal = document.getElementById(&#039;clbi-crop-modal&#039;);&lt;br /&gt;
    var cropImage = document.getElementById(&#039;clbi-crop-image&#039;);&lt;br /&gt;
    var pfpInput = document.getElementById(&#039;pref-pfp-input&#039;);&lt;br /&gt;
&lt;br /&gt;
    function openGallery() {&lt;br /&gt;
        gModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
        api.get({&lt;br /&gt;
            action: &#039;query&#039;,&lt;br /&gt;
            titles: &#039;파일:Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
            prop: &#039;imageinfo&#039;,&lt;br /&gt;
            iiprop: &#039;url|timestamp&#039;,&lt;br /&gt;
            iilimit: 6&lt;br /&gt;
        }).then(function(data) {&lt;br /&gt;
            var pages = data.query.pages;&lt;br /&gt;
            var page = pages[Object.keys(pages)[0]];&lt;br /&gt;
            if (!page.imageinfo || page.imageinfo.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
            var historyEl = document.getElementById(&#039;clbi-gallery-history&#039;);&lt;br /&gt;
            var sectionEl = document.getElementById(&#039;clbi-gallery-history-section&#039;);&lt;br /&gt;
            historyEl.innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            page.imageinfo.forEach(function(info, idx) {&lt;br /&gt;
                var wrap = document.createElement(&#039;div&#039;);&lt;br /&gt;
                wrap.style.cssText = &#039;position:relative;cursor:pointer;&#039;;&lt;br /&gt;
&lt;br /&gt;
                var img = document.createElement(&#039;img&#039;);&lt;br /&gt;
                img.src = info.url;&lt;br /&gt;
                img.style.cssText =&lt;br /&gt;
                    &#039;width:72px;height:72px;object-fit:cover;border-radius:8px;border:2px solid #444;flex-shrink:0;&#039;;&lt;br /&gt;
&lt;br /&gt;
                if (idx === 0) {&lt;br /&gt;
                    img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                    var badge = document.createElement(&#039;div&#039;);&lt;br /&gt;
                    badge.textContent = &#039;현재&#039;;&lt;br /&gt;
                    badge.style.cssText =&lt;br /&gt;
                        &#039;position:absolute;bottom:4px;left:50%;transform:translateX(-50%);background:#854369;color:#fff;font-size:9px;padding:1px 6px;border-radius:10px;&#039;;&lt;br /&gt;
                    wrap.appendChild(badge);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseenter&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#854369&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;mouseleave&#039;, function() {&lt;br /&gt;
                    if (idx !== 0) img.style.borderColor = &#039;#444&#039;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                img.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
                    fetch(info.url)&lt;br /&gt;
                        .then(function(r) {&lt;br /&gt;
                            return r.blob();&lt;br /&gt;
                        })&lt;br /&gt;
                        .then(function(blob) {&lt;br /&gt;
                            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
                            gModal.style.display = &#039;none&#039;;&lt;br /&gt;
                            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                wrap.appendChild(img);&lt;br /&gt;
                historyEl.appendChild(wrap);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            sectionEl.style.display = &#039;block&#039;;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openCrop(src) {&lt;br /&gt;
        cropImage.src = src;&lt;br /&gt;
        cModal.style.display = &#039;flex&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            cropper = new Cropper(cropImage, {&lt;br /&gt;
                aspectRatio: 1,&lt;br /&gt;
                viewMode: 1,&lt;br /&gt;
                dragMode: &#039;move&#039;,&lt;br /&gt;
                autoCropArea: 0.8,&lt;br /&gt;
                cropBoxResizable: true,&lt;br /&gt;
                cropBoxMovable: true&lt;br /&gt;
            });&lt;br /&gt;
        }, 150);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;pref-pfp-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        openGallery();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-upload-btn&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        pfpInput.click();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-gallery-close&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    pfpInput.addEventListener(&#039;change&#039;, function() {&lt;br /&gt;
        var file = this.files[0];&lt;br /&gt;
        if (!file) return;&lt;br /&gt;
&lt;br /&gt;
        gModal.style.display = &#039;none&#039;;&lt;br /&gt;
&lt;br /&gt;
        var reader = new FileReader();&lt;br /&gt;
        reader.onload = function(e) {&lt;br /&gt;
            openCrop(e.target.result);&lt;br /&gt;
        };&lt;br /&gt;
        reader.readAsDataURL(file);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-cancel&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        cModal.style.display = &#039;none&#039;;&lt;br /&gt;
        if (cropper) {&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
        }&lt;br /&gt;
        pfpInput.value = &#039;&#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.getElementById(&#039;clbi-crop-confirm&#039;).addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        if (!cropper) return;&lt;br /&gt;
&lt;br /&gt;
        var canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });&lt;br /&gt;
        if (!canvas) return;&lt;br /&gt;
&lt;br /&gt;
        canvas.toBlob(function(blob) {&lt;br /&gt;
            selectedFile = new File([blob], &#039;profile.png&#039;, { type: &#039;image/png&#039; });&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-preview&#039;).src = URL.createObjectURL(blob);&lt;br /&gt;
            cModal.style.display = &#039;none&#039;;&lt;br /&gt;
            cropper.destroy();&lt;br /&gt;
            cropper = null;&lt;br /&gt;
            document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;✓ 사진 선택됨&#039;;&lt;br /&gt;
        }, &#039;image/png&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    var emailSaveBtn = document.getElementById(&#039;pref-email-save&#039;);&lt;br /&gt;
    if (emailSaveBtn) {&lt;br /&gt;
        emailSaveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
            var statusEl = document.getElementById(&#039;pref-email-status&#039;);&lt;br /&gt;
            var newEmail = document.getElementById(&#039;pref-new-email&#039;).value;&lt;br /&gt;
            var password = document.getElementById(&#039;pref-email-password&#039;).value;&lt;br /&gt;
&lt;br /&gt;
            if (!newEmail || !password) {&lt;br /&gt;
                statusEl.textContent = &#039;이메일과 비밀번호를 입력해주세요.&#039;;&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            statusEl.textContent = &#039;변경 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;changeemail&#039;,&lt;br /&gt;
                email: newEmail,&lt;br /&gt;
                password: password&lt;br /&gt;
            }).then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 이메일 변경됨&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-new-email&#039;).value = &#039;&#039;;&lt;br /&gt;
                document.getElementById(&#039;pref-email-password&#039;).value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 3000);&lt;br /&gt;
            }).fail(function(code, data) {&lt;br /&gt;
                var msg = data &amp;amp;&amp;amp; data.error &amp;amp;&amp;amp; data.error.info ? data.error.info : &#039;변경 실패&#039;;&lt;br /&gt;
                statusEl.textContent = msg;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    saveBtn.addEventListener(&#039;click&#039;, function() {&lt;br /&gt;
        var statusEl = document.getElementById(&#039;pref-status&#039;);&lt;br /&gt;
        statusEl.textContent = &#039;저장 중...&#039;;&lt;br /&gt;
&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        if (selectedFile) {&lt;br /&gt;
            var username = mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;upload&#039;,&lt;br /&gt;
                    filename: &#039;Pfp-&#039; + username + &#039;.png&#039;,&lt;br /&gt;
                    ignorewarnings: true,&lt;br /&gt;
                    file: selectedFile,&lt;br /&gt;
                    format: &#039;json&#039;&lt;br /&gt;
                }, {&lt;br /&gt;
                    contentType: &#039;multipart/form-data&#039;&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var fields = [&#039;name&#039;, &#039;discord&#039;, &#039;role&#039;, &#039;bio&#039;];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; fields.length; i++) {&lt;br /&gt;
            var el = document.getElementById(&#039;pref-&#039; + fields[i]);&lt;br /&gt;
            if (!el) continue;&lt;br /&gt;
&lt;br /&gt;
            promises.push(&lt;br /&gt;
                api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                    action: &#039;options&#039;,&lt;br /&gt;
                    optionname: &#039;profile-&#039; + fields[i],&lt;br /&gt;
                    optionvalue: el.value&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $.when.apply($, promises)&lt;br /&gt;
            .then(function() {&lt;br /&gt;
                statusEl.textContent = &#039;✓ 저장됨&#039;;&lt;br /&gt;
                selectedFile = null;&lt;br /&gt;
                document.getElementById(&#039;pref-pfp-btn&#039;).textContent = &#039;사진 선택&#039;;&lt;br /&gt;
&lt;br /&gt;
                setTimeout(function() {&lt;br /&gt;
                    statusEl.textContent = &#039;&#039;;&lt;br /&gt;
                }, 2000);&lt;br /&gt;
            })&lt;br /&gt;
            .fail(function() {&lt;br /&gt;
                statusEl.textContent = &#039;저장 실패&#039;;&lt;br /&gt;
            });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Banner / CRT Page Monitor thumbnail slices&lt;br /&gt;
   - base 이미지는 틀에 들어간 파일 문법 그대로 사용&lt;br /&gt;
   - slice 레이어에는 300px MediaWiki 썸네일만 삽입&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function ($, mw) {&lt;br /&gt;
    var thumbCache = {};&lt;br /&gt;
&lt;br /&gt;
    function parseSliceWidth(value) {&lt;br /&gt;
        var parsed = parseInt(value, 10);&lt;br /&gt;
&lt;br /&gt;
        if (!isFinite(parsed) || parsed &amp;lt; 120) {&lt;br /&gt;
            return 300;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parsed;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getImageSrc(img) {&lt;br /&gt;
        return img ? (img.currentSrc || img.getAttribute(&#039;src&#039;) || img.src || &#039;&#039;) : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFileNameFromSrc(src) {&lt;br /&gt;
        var a;&lt;br /&gt;
        var parts;&lt;br /&gt;
        var fileName;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        a = document.createElement(&#039;a&#039;);&lt;br /&gt;
        a.href = src;&lt;br /&gt;
&lt;br /&gt;
        parts = (a.pathname || &#039;&#039;).split(&#039;/&#039;).filter(function (part) {&lt;br /&gt;
            return !!part;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!parts.length) return &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        fileName = parts.pop();&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * MediaWiki thumb URL 예시:&lt;br /&gt;
         * /images/thumb/a/ab/File.png/1000px-File.png&lt;br /&gt;
         * /images/thumb/a/ab/File.svg/1000px-File.svg.png&lt;br /&gt;
         *&lt;br /&gt;
         * 이 경우 실제 파일명은 마지막 조각이 아니라 그 앞 조각이다.&lt;br /&gt;
         */&lt;br /&gt;
        if (/^\d+px-/.test(fileName) &amp;amp;&amp;amp; parts.length) {&lt;br /&gt;
            fileName = parts.pop();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        fileName = fileName.replace(/^\d+px-/, &#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
        try {&lt;br /&gt;
            fileName = decodeURIComponent(fileName);&lt;br /&gt;
        } catch (e) {}&lt;br /&gt;
&lt;br /&gt;
        return fileName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function resolveThumbUrl(img, width, callback) {&lt;br /&gt;
        var src = getImageSrc(img);&lt;br /&gt;
        var fileName = getFileNameFromSrc(src);&lt;br /&gt;
        var cacheKey;&lt;br /&gt;
        var entry;&lt;br /&gt;
&lt;br /&gt;
        if (!src) return;&lt;br /&gt;
&lt;br /&gt;
        if (!fileName || !mw || !mw.loader) {&lt;br /&gt;
            callback(src);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cacheKey = fileName + &#039;|&#039; + width;&lt;br /&gt;
        entry = thumbCache[cacheKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
            if (entry.resolved) {&lt;br /&gt;
                callback(entry.url || src);&lt;br /&gt;
            } else {&lt;br /&gt;
                entry.callbacks.push(callback);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        entry = {&lt;br /&gt;
            resolved: false,&lt;br /&gt;
            url: &#039;&#039;,&lt;br /&gt;
            callbacks: [callback]&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        thumbCache[cacheKey] = entry;&lt;br /&gt;
&lt;br /&gt;
        function finish(url) {&lt;br /&gt;
            var callbacks = entry.callbacks.slice();&lt;br /&gt;
            var i;&lt;br /&gt;
&lt;br /&gt;
            entry.resolved = true;&lt;br /&gt;
            entry.url = url || src;&lt;br /&gt;
            entry.callbacks = [];&lt;br /&gt;
&lt;br /&gt;
            for (i = 0; i &amp;lt; callbacks.length; i++) {&lt;br /&gt;
                callbacks[i](entry.url);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using(&#039;mediawiki.api&#039;).done(function () {&lt;br /&gt;
            var api = new mw.Api();&lt;br /&gt;
&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                titles: &#039;File:&#039; + fileName,&lt;br /&gt;
                prop: &#039;imageinfo&#039;,&lt;br /&gt;
                iiprop: &#039;url&#039;,&lt;br /&gt;
                iiurlwidth: width,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
                var page;&lt;br /&gt;
                var info;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    data &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages &amp;amp;&amp;amp;&lt;br /&gt;
                    data.query.pages.length&lt;br /&gt;
                ) {&lt;br /&gt;
                    page = data.query.pages[0];&lt;br /&gt;
&lt;br /&gt;
                    if (&lt;br /&gt;
                        page &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo &amp;amp;&amp;amp;&lt;br /&gt;
                        page.imageinfo.length&lt;br /&gt;
                    ) {&lt;br /&gt;
                        info = page.imageinfo[0];&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                finish((info &amp;amp;&amp;amp; (info.thumburl || info.url)) || src);&lt;br /&gt;
            }).fail(function () {&lt;br /&gt;
                finish(src);&lt;br /&gt;
            });&lt;br /&gt;
        }).fail(function () {&lt;br /&gt;
            finish(src);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySliceImages(frame, thumbUrl) {&lt;br /&gt;
        var slices;&lt;br /&gt;
        var i;&lt;br /&gt;
        var img;&lt;br /&gt;
&lt;br /&gt;
        if (!frame || !thumbUrl) return;&lt;br /&gt;
&lt;br /&gt;
        slices = frame.querySelectorAll(&#039;.crt-page-monitor-slice&#039;);&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; slices.length; i++) {&lt;br /&gt;
            slices[i].innerHTML = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
            img = document.createElement(&#039;img&#039;);&lt;br /&gt;
            img.className = &#039;crt-page-monitor-slice-img&#039;;&lt;br /&gt;
            img.src = thumbUrl;&lt;br /&gt;
            img.alt = &#039;&#039;;&lt;br /&gt;
            img.decoding = &#039;async&#039;;&lt;br /&gt;
            img.loading = &#039;eager&#039;;&lt;br /&gt;
            img.setAttribute(&#039;aria-hidden&#039;, &#039;true&#039;);&lt;br /&gt;
&lt;br /&gt;
            slices[i].appendChild(img);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frame.setAttribute(&#039;data-crt-slices-ready&#039;, &#039;1&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrame(frame) {&lt;br /&gt;
        var baseImg;&lt;br /&gt;
        var width;&lt;br /&gt;
&lt;br /&gt;
        if (!frame) return;&lt;br /&gt;
        if (frame.getAttribute(&#039;data-crt-slices-ready&#039;) === &#039;1&#039;) return;&lt;br /&gt;
&lt;br /&gt;
        baseImg = frame.querySelector(&#039;.crt-page-monitor-image-base img&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!baseImg) return;&lt;br /&gt;
&lt;br /&gt;
        width = parseSliceWidth(frame.getAttribute(&#039;data-crt-slice-width&#039;));&lt;br /&gt;
&lt;br /&gt;
        resolveThumbUrl(baseImg, width, function (thumbUrl) {&lt;br /&gt;
            if (!frame || !frame.parentNode) return;&lt;br /&gt;
            applySliceImages(frame, thumbUrl);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initBannerFrames(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        var frames = scope.querySelectorAll(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
        var i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; frames.length; i++) {&lt;br /&gt;
            initBannerFrame(frames[i]);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initBannerFrames(document);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (mw &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($content) {&lt;br /&gt;
            initBannerFrames($content &amp;amp;&amp;amp; $content[0] ? $content[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})(jQuery, window.mw);&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Tab System — Q/E 단축키 탭 전환&lt;br /&gt;
   글리치 플리커 + RGB split + 방향 슬라이드&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
var keydownBound = false;&lt;br /&gt;
&lt;br /&gt;
    function initDocTabs() {&lt;br /&gt;
        var tabBars = document.querySelectorAll(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
        if (!tabBars.length) return;&lt;br /&gt;
&lt;br /&gt;
        tabBars.forEach(function (bar) {&lt;br /&gt;
            if (bar.getAttribute(&#039;data-tabs-init&#039;)) return;&lt;br /&gt;
            bar.setAttribute(&#039;data-tabs-init&#039;, &#039;1&#039;);&lt;br /&gt;
&lt;br /&gt;
            var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
            if (!tabs.length) return;&lt;br /&gt;
&lt;br /&gt;
            var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
            var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
            if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
            if (!display) return;&lt;br /&gt;
&lt;br /&gt;
            tabs.forEach(function (tab, i) {&lt;br /&gt;
                tab.addEventListener(&#039;click&#039;, function () {&lt;br /&gt;
                    var currentIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                        return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                    });&lt;br /&gt;
                    if (currentIdx === i) return;&lt;br /&gt;
                    switchTab(tabs, display, i, i &amp;gt; currentIdx ? 1 : -1);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var initIdx = tabs.findIndex(function (t) { return t.classList.contains(&#039;active&#039;); });&lt;br /&gt;
            if (initIdx !== -1) {&lt;br /&gt;
                var initRef = tabs[initIdx].dataset.ref;&lt;br /&gt;
                var initEl = initRef ? document.getElementById(initRef) : null;&lt;br /&gt;
                display.innerHTML = initEl ? initEl.innerHTML : (tabs[initIdx].dataset.content || &#039;&#039;);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if (!keydownBound) {&lt;br /&gt;
            keydownBound = true;&lt;br /&gt;
            document.addEventListener(&#039;keydown&#039;, function (e) {&lt;br /&gt;
                var tag = document.activeElement.tagName;&lt;br /&gt;
                if (tag === &#039;INPUT&#039; || tag === &#039;TEXTAREA&#039;) return;&lt;br /&gt;
&lt;br /&gt;
                var bar = document.querySelector(&#039;.doc-tab-bar&#039;);&lt;br /&gt;
                if (!bar) return;&lt;br /&gt;
                var tabs = Array.from(bar.querySelectorAll(&#039;.doc-tab&#039;));&lt;br /&gt;
&lt;br /&gt;
                var panel = bar.closest(&#039;.doc-panel&#039;);&lt;br /&gt;
                var display = panel ? panel.querySelector(&#039;.doc-display&#039;) : null;&lt;br /&gt;
                if (!display) display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
                if (!display) return;&lt;br /&gt;
&lt;br /&gt;
                var activeIdx = tabs.findIndex(function (t) {&lt;br /&gt;
                    return t.classList.contains(&#039;active&#039;);&lt;br /&gt;
                });&lt;br /&gt;
                if (activeIdx === -1) return;&lt;br /&gt;
&lt;br /&gt;
                if (e.key === &#039;q&#039; || e.key === &#039;Q&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var prev = (activeIdx - 1 + tabs.length) % tabs.length;&lt;br /&gt;
                    if (prev !== activeIdx) switchTab(tabs, display, prev, -1);&lt;br /&gt;
                } else if (e.key === &#039;e&#039; || e.key === &#039;E&#039;) {&lt;br /&gt;
                    e.preventDefault();&lt;br /&gt;
                    var next = (activeIdx + 1) % tabs.length;&lt;br /&gt;
                    if (next !== activeIdx) switchTab(tabs, display, next, 1);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var isAnimating = false;&lt;br /&gt;
&lt;br /&gt;
    function switchTab(tabs, display, nextIdx, dir) {&lt;br /&gt;
        if (isAnimating) return;&lt;br /&gt;
        isAnimating = true;&lt;br /&gt;
&lt;br /&gt;
        tabs.forEach(function (t) { t.classList.remove(&#039;active&#039;); });&lt;br /&gt;
        tabs[nextIdx].classList.add(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
        var ref = tabs[nextIdx].dataset.ref;&lt;br /&gt;
        var nextContent;&lt;br /&gt;
        if (ref) {&lt;br /&gt;
            var refEl = document.getElementById(ref);&lt;br /&gt;
            nextContent = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            nextContent = tabs[nextIdx].dataset.content || &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        glitchOut(display, dir, function () {&lt;br /&gt;
            display.innerHTML = nextContent;&lt;br /&gt;
            glitchIn(display, dir, function () {&lt;br /&gt;
                isAnimating = false;&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchOut(el, dir, cb) {&lt;br /&gt;
        var duration = 160;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var slideX = dir * 16;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = p * p;&lt;br /&gt;
&lt;br /&gt;
            var tx = slideX * ease;&lt;br /&gt;
            var skew = dir * ease * 1.0;&lt;br /&gt;
            var opacity = 1 - ease;&lt;br /&gt;
            var rgb = ease * 5;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.75)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.65)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + (1 + ease * 0.25) + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.opacity = &#039;0&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function glitchIn(el, dir, cb) {&lt;br /&gt;
        var duration = 200;&lt;br /&gt;
        var start = null;&lt;br /&gt;
        var startX = -dir * 16;&lt;br /&gt;
&lt;br /&gt;
        el.style.transform = &#039;translateX(&#039; + startX + &#039;px) skewX(&#039; + (-dir * 1.0) + &#039;deg)&#039;;&lt;br /&gt;
        el.style.opacity = &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
        function step(ts) {&lt;br /&gt;
            if (!start) start = ts;&lt;br /&gt;
            var p = Math.min((ts - start) / duration, 1);&lt;br /&gt;
            var ease = 1 - Math.pow(1 - p, 3);&lt;br /&gt;
&lt;br /&gt;
            var tx = startX * (1 - ease);&lt;br /&gt;
            var skew = -dir * 1.0 * (1 - ease);&lt;br /&gt;
            var opacity = ease;&lt;br /&gt;
            var rgb = (1 - ease) * 3;&lt;br /&gt;
            var brightness = 1 + (1 - ease) * 0.35;&lt;br /&gt;
&lt;br /&gt;
            el.style.transform = &#039;translateX(&#039; + tx + &#039;px) skewX(&#039; + skew + &#039;deg)&#039;;&lt;br /&gt;
            el.style.opacity = opacity;&lt;br /&gt;
            el.style.filter =&lt;br /&gt;
                &#039;drop-shadow(&#039; + (-rgb) + &#039;px 0 0 rgba(80,160,255,0.65)) &#039; +&lt;br /&gt;
                &#039;drop-shadow(&#039; + rgb + &#039;px 0 0 rgba(255,55,90,0.55)) &#039; +&lt;br /&gt;
                &#039;brightness(&#039; + brightness + &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
            if (p &amp;lt; 1) {&lt;br /&gt;
                requestAnimationFrame(step);&lt;br /&gt;
            } else {&lt;br /&gt;
                el.style.transform = &#039;&#039;;&lt;br /&gt;
                el.style.opacity = &#039;&#039;;&lt;br /&gt;
                el.style.filter = &#039;&#039;;&lt;br /&gt;
                cb();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        requestAnimationFrame(step);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
if (document.readyState === &#039;loading&#039;) {&lt;br /&gt;
    document.addEventListener(&#039;DOMContentLoaded&#039;, initDocTabs);&lt;br /&gt;
} else {&lt;br /&gt;
    initDocTabs();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        initDocTabs();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   Doc Section Switch — 좌측 섹션 전환&lt;br /&gt;
   ========================================= */&lt;br /&gt;
&lt;br /&gt;
$(document).on(&#039;click&#039;, &#039;.doc-nav-item[data-section]&#039;, function () {&lt;br /&gt;
    var name = $(this).attr(&#039;data-section&#039;);&lt;br /&gt;
    var display = document.getElementById(&#039;doc-main-display&#039;);&lt;br /&gt;
    var titleEl = document.getElementById(&#039;doc-center-title&#039;);&lt;br /&gt;
    var tabBar = document.getElementById(&#039;doc-tab-bar-text&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!display) return;&lt;br /&gt;
&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section]&#039;).removeClass(&#039;active&#039;);&lt;br /&gt;
    $(&#039;.doc-nav-item[data-section=&amp;quot;&#039; + name + &#039;&amp;quot;]&#039;).addClass(&#039;active&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (name === &#039;text&#039;) {&lt;br /&gt;
        if (titleEl) titleEl.textContent = &#039;개요&#039;;&lt;br /&gt;
        if (tabBar) $(tabBar).show();&lt;br /&gt;
        var activeTab = tabBar ? tabBar.querySelector(&#039;.doc-tab.active&#039;) : null;&lt;br /&gt;
        if (!activeTab &amp;amp;&amp;amp; tabBar) activeTab = tabBar.querySelector(&#039;.doc-tab&#039;);&lt;br /&gt;
        if (activeTab) {&lt;br /&gt;
            var ref = activeTab.dataset.ref;&lt;br /&gt;
            var refEl = ref ? document.getElementById(ref) : null;&lt;br /&gt;
            display.innerHTML = refEl ? refEl.innerHTML : (activeTab.dataset.content || &#039;&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        if (titleEl) titleEl.textContent = name === &#039;factions&#039; ? &#039;세력&#039; : name === &#039;people&#039; ? &#039;인물&#039; : name;&lt;br /&gt;
        if (tabBar) $(tabBar).hide();&lt;br /&gt;
        var refEl = document.getElementById(&#039;doc-content-&#039; + name);&lt;br /&gt;
        display.innerHTML = refEl ? refEl.innerHTML : &#039;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
   CRT WebGL Renderer — cool-retro-term IBM DOS style&lt;br /&gt;
   ========================================= */&lt;br /&gt;
(function () {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    function createNoiseTexture(gl) {&lt;br /&gt;
        var size = 512;&lt;br /&gt;
        var data = new Uint8Array(size * size * 4);&lt;br /&gt;
        var s = 12345;&lt;br /&gt;
        function rand() {&lt;br /&gt;
            s = (s * 1664525 + 1013904223) &amp;amp; 0xffffffff;&lt;br /&gt;
            return (s &amp;gt;&amp;gt;&amp;gt; 0) / 0xffffffff;&lt;br /&gt;
        }&lt;br /&gt;
        for (var i = 0; i &amp;lt; data.length; i++) {&lt;br /&gt;
            data[i] = (rand() * 255) | 0;&lt;br /&gt;
        }&lt;br /&gt;
        var tex = gl.createTexture();&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, tex);&lt;br /&gt;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
        return tex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var VERT = [&lt;br /&gt;
        &#039;attribute vec2 a_pos;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);&#039;,&lt;br /&gt;
        &#039;  gl_Position = vec4(a_pos, 0.0, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    var FRAG = [&lt;br /&gt;
        &#039;precision mediump float;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_tex;&#039;,&lt;br /&gt;
        &#039;uniform sampler2D u_noise;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_res;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_imgSize;&#039;,&lt;br /&gt;
        &#039;uniform float u_time;&#039;,&lt;br /&gt;
        &#039;uniform vec2 u_noiseScale;&#039;,&lt;br /&gt;
        &#039;varying vec2 v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float sum2(vec2 v) { return v.x + v.y; }&#039;,&lt;br /&gt;
        &#039;float min2(vec2 v) { return min(v.x, v.y); }&#039;,&lt;br /&gt;
        &#039;float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 coverUV(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  float imgAR = u_imgSize.x / u_imgSize.y;&#039;,&lt;br /&gt;
        &#039;  float scrAR = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  float scale = imgAR / scrAR;&#039;,&lt;br /&gt;
        &#039;  float offsetY = (1.0 - scale) * 0.5;&#039;,&lt;br /&gt;
        &#039;  return vec2(uv.x, uv.y * scale + offsetY);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 barrel(vec2 v, vec2 cc, float k) {&#039;,&lt;br /&gt;
        &#039;  float ar = u_res.x / u_res.y;&#039;,&lt;br /&gt;
        &#039;  vec2 c2 = cc;&#039;,&lt;br /&gt;
        &#039;  if (ar &amp;gt; 1.0) c2.x /= ar; else c2.y *= ar;&#039;,&lt;br /&gt;
        &#039;  float dist = dot(c2, c2) * k;&#039;,&lt;br /&gt;
        &#039;  return v - cc * (1.0 + dist) * dist;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleInitialNoise(float t) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, vec2(fract(t/2048.0), fract(t/1048576.0)));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec4 sampleScreenNoise(vec2 uv) {&#039;,&lt;br /&gt;
        &#039;  return texture2D(u_noise, u_noiseScale * uv);&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyRgbShift(vec2 texUV, float shift) {&#039;,&lt;br /&gt;
        &#039;  vec2 d = vec2(shift, 0.0);&#039;,&lt;br /&gt;
        &#039;  vec3 r = texture2D(u_tex, clamp(texUV + d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 c = texture2D(u_tex, texUV).rgb;&#039;,&lt;br /&gt;
        &#039;  vec3 l = texture2D(u_tex, clamp(texUV - d, 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  return vec3(&#039;,&lt;br /&gt;
        &#039;    l.r*0.10 + r.r*0.30 + c.r*0.60,&#039;,&lt;br /&gt;
        &#039;    l.g*0.20 + r.g*0.20 + c.g*0.60,&#039;,&lt;br /&gt;
        &#039;    l.b*0.30 + r.b*0.10 + c.b*0.60&#039;,&lt;br /&gt;
        &#039;  );&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyBloom(vec2 texUV, float strength) {&#039;,&lt;br /&gt;
        &#039;  vec2 px = 2.0 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 acc = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  0.0), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0,  px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( 0.0, -px.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x,  px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2( px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  acc += texture2D(u_tex, clamp(texUV + vec2(-px.x, -px.y), 0.0, 1.0)).rgb * 0.5;&#039;,&lt;br /&gt;
        &#039;  return acc / 6.0 * strength;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec3 applyScanlines(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
        &#039;  float line = mod(uv.y * u_res.y, 2.0);&#039;,&lt;br /&gt;
        &#039;  vec3 hi = ((1.0 + 0.30) - 0.2 * col) * col;&#039;,&lt;br /&gt;
        &#039;  vec3 lo = ((1.0 - 0.30) + 0.1 * col) * col;&#039;,&lt;br /&gt;
        &#039;  return line &amp;lt; 1.0 ? lo : hi;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
&#039;vec3 applyRasterization(vec2 uv, vec3 col) {&#039;,&lt;br /&gt;
&#039;  float t = u_time;&#039;,&lt;br /&gt;
&#039;  vec2 noiseUV = uv + vec2(fract(t * 0.030), fract(t * 0.060));&#039;,&lt;br /&gt;
&#039;  float wobbleX = (texture2D(u_noise, noiseUV * 0.8).r - 0.5) * 0.0018;&#039;,&lt;br /&gt;
&#039;  float wobbleY = (texture2D(u_noise, noiseUV * 0.8 + 0.5).r - 0.5) * 0.0008;&#039;,&lt;br /&gt;
&#039;  vec2 wobbledUV = clamp(uv + vec2(wobbleX, wobbleY), 0.0, 1.0);&#039;,&lt;br /&gt;
&#039;  vec3 wobbled = texture2D(u_tex, wobbledUV).rgb;&#039;,&lt;br /&gt;
&#039;  return mix(col, wobbled, 0.35);&#039;,&lt;br /&gt;
&#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;float glowingLine(vec2 uv, float t) {&#039;,&lt;br /&gt;
&#039;  float pos = fract(t * 0.2);&#039;,&lt;br /&gt;
&#039;  float lineY = pos * (u_res.y + 330.0) - 120.0;&#039;,&lt;br /&gt;
        &#039;  float y = uv.y * u_res.y;&#039;,&lt;br /&gt;
        &#039;  return fract(smoothstep(-300.0, 0.0, y - lineY));&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;vec2 applyHSync(vec2 uv, vec4 noise, float strength) {&#039;,&lt;br /&gt;
        &#039;  float randval = strength - noise.r;&#039;,&lt;br /&gt;
        &#039;  float scale = step(0.0, randval) * randval * strength;&#039;,&lt;br /&gt;
        &#039;  float freq = mix(4.0, 40.0, noise.g);&#039;,&lt;br /&gt;
        &#039;  uv.x += sin((uv.y + u_time * 0.001) * freq) * scale;&#039;,&lt;br /&gt;
        &#039;  return uv;&#039;,&lt;br /&gt;
        &#039;}&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;void main() {&#039;,&lt;br /&gt;
        &#039;  vec2 cc = vec2(0.5) - v_uv;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float curvature = 0.18;&#039;,&lt;br /&gt;
        &#039;  vec2 uv = barrel(v_uv, cc, curvature);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float inScreen = min2(step(vec2(0.0), uv) - step(vec2(1.0), uv));&#039;,&lt;br /&gt;
        &#039;  if (inScreen &amp;lt; 0.5) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 texUV = clamp(coverUV(uv), 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec4 initNoise = sampleInitialNoise(u_time);&#039;,&lt;br /&gt;
        &#039;  vec4 screenNoise = sampleScreenNoise(uv);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV = applyHSync(texUV, initNoise, 0.006);&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  texUV += (vec2(screenNoise.b, screenNoise.a) - 0.5) * 0.0006;&#039;,&lt;br /&gt;
        &#039;  texUV = clamp(texUV, 0.0, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec3 col = applyRgbShift(texUV, 0.003);&#039;,&lt;br /&gt;
        &#039;  col += applyBloom(texUV, 0.22);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 bpx = 1.5 / u_res;&#039;,&lt;br /&gt;
        &#039;  vec3 blurCol = vec3(0.0);&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,   -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x, -bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  0.0  ), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2(-bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( 0.0,    bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  blurCol += texture2D(u_tex, clamp(texUV + vec2( bpx.x,  bpx.y), 0.0, 1.0)).rgb;&#039;,&lt;br /&gt;
        &#039;  col = mix(col, blurCol / 8.0, 0.40);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = applyScanlines(uv, col);&#039;,&lt;br /&gt;
        &#039;  col = applyRasterization(texUV, col);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float glow = glowingLine(uv, u_time);&#039;,&lt;br /&gt;
&#039;  col += glow * 0.08 * vec3(0.85, 0.95, 1.0);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float dist = length(cc);&#039;,&lt;br /&gt;
        &#039;  col += screenNoise.a * 0.07 * (1.0 - dist * 1.3);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  float grey = rgb2grey(col);&#039;,&lt;br /&gt;
        &#039;  vec3 phosphor = vec3(0.75, 0.88, 1.0);&#039;,&lt;br /&gt;
        &#039;  col = mix(col, grey * phosphor, 0.35);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  vec2 vig = v_uv * (1.0 - v_uv);&#039;,&lt;br /&gt;
        &#039;  col *= pow(vig.x * vig.y * 15.0, 0.25);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col *= 1.0 + (initNoise.g - 0.5) * 0.06;&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col += vec3(0.012) * (1.0 - dist) * (1.0 - dist);&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  col = pow(clamp(col, 0.0, 1.0), vec3(0.90));&#039;,&lt;br /&gt;
&lt;br /&gt;
        &#039;  gl_FragColor = vec4(col, 1.0);&#039;,&lt;br /&gt;
        &#039;}&#039;&lt;br /&gt;
    ].join(&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    function initCRTCanvas(screen, imgEl) {&lt;br /&gt;
        var existing = screen.querySelector(&#039;.crt-webgl-canvas&#039;);&lt;br /&gt;
        if (existing) existing.remove();&lt;br /&gt;
&lt;br /&gt;
        var canvas = document.createElement(&#039;canvas&#039;);&lt;br /&gt;
        canvas.className = &#039;crt-webgl-canvas&#039;;&lt;br /&gt;
        canvas.style.cssText = &#039;position:absolute;inset:0;width:100%;height:100%;z-index:19;pointer-events:none;display:block;&#039;;&lt;br /&gt;
        screen.appendChild(canvas);&lt;br /&gt;
&lt;br /&gt;
        var gl = canvas.getContext(&#039;webgl&#039;) || canvas.getContext(&#039;experimental-webgl&#039;);&lt;br /&gt;
        if (!gl) return;&lt;br /&gt;
&lt;br /&gt;
        function compile(type, src) {&lt;br /&gt;
            var s = gl.createShader(type);&lt;br /&gt;
            gl.shaderSource(s, src);&lt;br /&gt;
            gl.compileShader(s);&lt;br /&gt;
            if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {&lt;br /&gt;
                console.error(&#039;[CRT shader]&#039;, gl.getShaderInfoLog(s));&lt;br /&gt;
            }&lt;br /&gt;
            return s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var prog = gl.createProgram();&lt;br /&gt;
        gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));&lt;br /&gt;
        gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));&lt;br /&gt;
        gl.linkProgram(prog);&lt;br /&gt;
        gl.useProgram(prog);&lt;br /&gt;
&lt;br /&gt;
        var buf = gl.createBuffer();&lt;br /&gt;
        gl.bindBuffer(gl.ARRAY_BUFFER, buf);&lt;br /&gt;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);&lt;br /&gt;
        var aPos = gl.getAttribLocation(prog, &#039;a_pos&#039;);&lt;br /&gt;
        gl.enableVertexAttribArray(aPos);&lt;br /&gt;
        gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);&lt;br /&gt;
&lt;br /&gt;
        var uTex     = gl.getUniformLocation(prog, &#039;u_tex&#039;);&lt;br /&gt;
        var uNoise   = gl.getUniformLocation(prog, &#039;u_noise&#039;);&lt;br /&gt;
        var uRes     = gl.getUniformLocation(prog, &#039;u_res&#039;);&lt;br /&gt;
        var uImgSize = gl.getUniformLocation(prog, &#039;u_imgSize&#039;);&lt;br /&gt;
        var uTime    = gl.getUniformLocation(prog, &#039;u_time&#039;);&lt;br /&gt;
        var uNoiseSc = gl.getUniformLocation(prog, &#039;u_noiseScale&#039;);&lt;br /&gt;
&lt;br /&gt;
        var imgTex = gl.createTexture();&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
        gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
        gl.activeTexture(gl.TEXTURE1);&lt;br /&gt;
        createNoiseTexture(gl);&lt;br /&gt;
&lt;br /&gt;
        var texReady = false;&lt;br /&gt;
        function uploadImg() {&lt;br /&gt;
            if (!imgEl || !imgEl.complete || !imgEl.naturalWidth) return;&lt;br /&gt;
            try {&lt;br /&gt;
                gl.activeTexture(gl.TEXTURE0);&lt;br /&gt;
                gl.bindTexture(gl.TEXTURE_2D, imgTex);&lt;br /&gt;
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgEl);&lt;br /&gt;
                texReady = true;&lt;br /&gt;
            } catch(e) { console.error(&#039;[CRT] tex:&#039;, e); }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var lastW = 0, lastH = 0;&lt;br /&gt;
        function resize() {&lt;br /&gt;
            var w = screen.offsetWidth, h = screen.offsetHeight;&lt;br /&gt;
            if (w === lastW &amp;amp;&amp;amp; h === lastH) return;&lt;br /&gt;
            lastW = w; lastH = h;&lt;br /&gt;
            canvas.width = w; canvas.height = h;&lt;br /&gt;
            gl.viewport(0, 0, w, h);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var raf;&lt;br /&gt;
        var t0 = performance.now();&lt;br /&gt;
&lt;br /&gt;
        function render() {&lt;br /&gt;
            raf = requestAnimationFrame(render);&lt;br /&gt;
            if (!texReady) { uploadImg(); return; }&lt;br /&gt;
            resize();&lt;br /&gt;
            var t = (performance.now() - t0) / 1000;&lt;br /&gt;
            gl.uniform1i(uTex, 0);&lt;br /&gt;
            gl.uniform1i(uNoise, 1);&lt;br /&gt;
            gl.uniform2f(uRes, canvas.width, canvas.height);&lt;br /&gt;
            gl.uniform2f(uImgSize, imgEl.naturalWidth, imgEl.naturalHeight);&lt;br /&gt;
            gl.uniform1f(uTime, t);&lt;br /&gt;
            gl.uniform2f(uNoiseSc, canvas.width / 512.0, canvas.height / 512.0);&lt;br /&gt;
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) { uploadImg(); }&lt;br /&gt;
        else { imgEl.addEventListener(&#039;load&#039;, uploadImg); }&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
        screen._crtCleanup = function () { cancelAnimationFrame(raf); };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initAllCRTScreens(root) {&lt;br /&gt;
        var scope = root &amp;amp;&amp;amp; root.querySelectorAll ? root : document;&lt;br /&gt;
        scope.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (screen) {&lt;br /&gt;
            if (screen.getAttribute(&#039;data-crt-webgl&#039;) === &#039;1&#039;) return;&lt;br /&gt;
            screen.setAttribute(&#039;data-crt-webgl&#039;, &#039;1&#039;);&lt;br /&gt;
            var frame = screen.closest(&#039;.crt-page-monitor-frame&#039;);&lt;br /&gt;
            if (!frame) return;&lt;br /&gt;
            var imgEl = frame.querySelector(&#039;.crt-page-monitor-slice-img, .crt-page-monitor-image-base img&#039;);&lt;br /&gt;
            if (imgEl &amp;amp;&amp;amp; imgEl.complete &amp;amp;&amp;amp; imgEl.naturalWidth) {&lt;br /&gt;
                initCRTCanvas(screen, imgEl);&lt;br /&gt;
            } else if (imgEl) {&lt;br /&gt;
                imgEl.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, imgEl); });&lt;br /&gt;
            } else {&lt;br /&gt;
                var obs = new MutationObserver(function () {&lt;br /&gt;
                    var img = frame.querySelector(&#039;.crt-page-monitor-slice-img&#039;);&lt;br /&gt;
                    if (!img) return;&lt;br /&gt;
                    obs.disconnect();&lt;br /&gt;
                    if (img.complete &amp;amp;&amp;amp; img.naturalWidth) {&lt;br /&gt;
                        initCRTCanvas(screen, img);&lt;br /&gt;
                    } else {&lt;br /&gt;
                        img.addEventListener(&#039;load&#039;, function () { initCRTCanvas(screen, img); });&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
                obs.observe(frame, { childList: true, subtree: true });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(function () { initAllCRTScreens(document); });&lt;br /&gt;
&lt;br /&gt;
    if (typeof mw !== &#039;undefined&#039; &amp;amp;&amp;amp; mw.hook) {&lt;br /&gt;
        mw.hook(&#039;wikipage.content&#039;).add(function ($c) {&lt;br /&gt;
            document.querySelectorAll(&#039;.crt-page-monitor-screen&#039;).forEach(function (s) {&lt;br /&gt;
                if (s._crtCleanup) s._crtCleanup();&lt;br /&gt;
                s.removeAttribute(&#039;data-crt-webgl&#039;);&lt;br /&gt;
            });&lt;br /&gt;
            initAllCRTScreens($c &amp;amp;&amp;amp; $c[0] ? $c[0] : document);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Common.js controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
(function (mw, $) {&lt;br /&gt;
    &#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
    if (window.ProgressSystemWebUiInitialized) return;&lt;br /&gt;
    window.ProgressSystemWebUiInitialized = true;&lt;br /&gt;
&lt;br /&gt;
    var api = null;&lt;br /&gt;
&lt;br /&gt;
    function withApi(done, fail) {&lt;br /&gt;
        if (api) {&lt;br /&gt;
            done(api);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!mw.loader || typeof mw.loader.using !== &#039;function&#039;) {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        mw.loader.using([&#039;mediawiki.api&#039;]).then(function () {&lt;br /&gt;
            api = new mw.Api();&lt;br /&gt;
            done(api);&lt;br /&gt;
        }, function () {&lt;br /&gt;
            if (typeof fail === &#039;function&#039;) fail();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var inFlightPageIds = new Set();&lt;br /&gt;
    var handledPageIds = new Set();&lt;br /&gt;
    var notificationQueue = [];&lt;br /&gt;
    var notificationActive = false;&lt;br /&gt;
    var summaryRequested = false;&lt;br /&gt;
    var currentSummary = null;&lt;br /&gt;
    var pendingSummary = null;&lt;br /&gt;
    var pendingOptions = null;&lt;br /&gt;
    var visibilityBound = false;&lt;br /&gt;
    var barTimerA = null;&lt;br /&gt;
    var barTimerB = null;&lt;br /&gt;
    var barTimerC = null;&lt;br /&gt;
&lt;br /&gt;
    function isLoggedIn() {&lt;br /&gt;
        return !!mw.config.get(&#039;wgUserName&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPageId() {&lt;br /&gt;
        var id = parseInt(mw.config.get(&#039;wgArticleId&#039;) || 0, 10);&lt;br /&gt;
        return Number.isFinite(id) ? id : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isRewardableClientSide() {&lt;br /&gt;
        if (!isLoggedIn()) return false;&lt;br /&gt;
        if (parseInt(mw.config.get(&#039;wgNamespaceNumber&#039;), 10) !== 0) return false;&lt;br /&gt;
        if (mw.config.get(&#039;wgIsMainPage&#039;)) return false;&lt;br /&gt;
        if (getPageId() &amp;lt;= 0) return false;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPanelHtml() {&lt;br /&gt;
        return &#039;&#039; +&lt;br /&gt;
            &#039;&amp;lt;div id=&amp;quot;progress-panel&amp;quot; class=&amp;quot;profile-progress-block is-syncing&amp;quot; aria-live=&amp;quot;polite&amp;quot; data-progress-state=&amp;quot;syncing&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-title-row&amp;quot; hidden&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-level-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-level-label&amp;quot;&amp;gt;SYNC&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-total-xp&amp;quot;&amp;gt;— XP&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-xp-bar&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-gain&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;div class=&amp;quot;progress-xp-fill&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-sub-row&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-xp-next&amp;quot;&amp;gt;SYNCING&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                    &#039;&amp;lt;span class=&amp;quot;progress-daily-xp&amp;quot;&amp;gt;TODAY —&amp;lt;/span&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
                &#039;&amp;lt;div class=&amp;quot;progress-discovery-row&amp;quot;&amp;gt;DISCOVERED —&amp;lt;/div&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getDividerHtml() {&lt;br /&gt;
        return &#039;&amp;lt;div id=&amp;quot;profile-progress-divider&amp;quot; class=&amp;quot;profile-divider&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setPanelSync($panel) {&lt;br /&gt;
        if (!$panel || !$panel.length) return;&lt;br /&gt;
&lt;br /&gt;
        $panel.addClass(&#039;is-syncing&#039;).removeClass(&#039;is-max-level&#039;).attr(&#039;data-progress-state&#039;, &#039;syncing&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-title-row&#039;).text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text(&#039;SYNC&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(&#039;— XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(&#039;SYNCING&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED —&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-fill&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
        $panel.find(&#039;.progress-xp-gain&#039;).css({ transition: &#039;none&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function placePanel($panel) {&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $userBox = $right.children(&#039;.clbi-right-box&#039;).first();&lt;br /&gt;
        if (!$userBox.length) return false;&lt;br /&gt;
&lt;br /&gt;
        var $buttonArea = $userBox.children(&#039;.clbi-right-content&#039;).first();&lt;br /&gt;
        var $oldFallback = $panel.closest(&#039;.progress-panel-fallback&#039;);&lt;br /&gt;
&lt;br /&gt;
        if ($buttonArea.length) {&lt;br /&gt;
            var $divider = $(&#039;#profile-progress-divider&#039;);&lt;br /&gt;
&lt;br /&gt;
            $panel.insertBefore($buttonArea);&lt;br /&gt;
&lt;br /&gt;
            if (!$divider.length) {&lt;br /&gt;
                $divider = $(getDividerHtml());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $divider.insertAfter($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $(&#039;#profile-progress-divider&#039;).remove();&lt;br /&gt;
            $userBox.append($panel);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($oldFallback.length &amp;amp;&amp;amp; !$oldFallback.find(&#039;#progress-panel&#039;).length) {&lt;br /&gt;
            $oldFallback.remove();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function ensurePanel() {&lt;br /&gt;
        if (!isLoggedIn()) return $();&lt;br /&gt;
&lt;br /&gt;
        var $right = $(&#039;#clbi-right-sidebar&#039;);&lt;br /&gt;
        if (!$right.length) return $();&lt;br /&gt;
&lt;br /&gt;
        var $panel = $(&#039;#progress-panel&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            $panel = $(getPanelHtml());&lt;br /&gt;
            if (!placePanel($panel)) return $();&lt;br /&gt;
            setPanelSync($panel);&lt;br /&gt;
        } else {&lt;br /&gt;
            $panel.addClass(&#039;profile-progress-block&#039;);&lt;br /&gt;
            placePanel($panel);&lt;br /&gt;
&lt;br /&gt;
            if (!currentSummary &amp;amp;&amp;amp; $panel.attr(&#039;data-progress-state&#039;) !== &#039;syncing&#039;) {&lt;br /&gt;
                setPanelSync($panel);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $(&#039;#progress-panel&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clampPercent(value) {&lt;br /&gt;
        return Math.max(0, Math.min(100, value || 0));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hasXpNotification(items) {&lt;br /&gt;
        if (!items || !items.length) return false;&lt;br /&gt;
        return items.some(function (item) {&lt;br /&gt;
            return item &amp;amp;&amp;amp; item.type === &#039;xp&#039; &amp;amp;&amp;amp; parseInt(item.amount || 0, 10) &amp;gt; 0;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function clearBarTimers() {&lt;br /&gt;
        [barTimerA, barTimerB, barTimerC].forEach(function (timer) {&lt;br /&gt;
            if (timer) clearTimeout(timer);&lt;br /&gt;
        });&lt;br /&gt;
        barTimerA = null;&lt;br /&gt;
        barTimerB = null;&lt;br /&gt;
        barTimerC = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setBarInstant($fill, $gain, percent) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
        percent = clampPercent(percent);&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: percent + &#039;%&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;none&#039;, left: &#039;0%&#039;, width: &#039;0%&#039;, opacity: 0 });&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
        $fill.css({ transition: &#039;&#039; });&lt;br /&gt;
        $gain.css({ transition: &#039;&#039; });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function animateGain($fill, $gain, fromPercent, toPercent, levelChanged) {&lt;br /&gt;
        clearBarTimers();&lt;br /&gt;
&lt;br /&gt;
        fromPercent = clampPercent(fromPercent);&lt;br /&gt;
        toPercent = clampPercent(toPercent);&lt;br /&gt;
&lt;br /&gt;
        $fill.css({ transition: &#039;none&#039;, width: fromPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
        if (levelChanged) {&lt;br /&gt;
            var firstDelta = Math.max(0, 100 - fromPercent);&lt;br /&gt;
&lt;br /&gt;
            $gain.css({&lt;br /&gt;
                transition: &#039;none&#039;,&lt;br /&gt;
                opacity: firstDelta &amp;gt; 0 ? 1 : 0,&lt;br /&gt;
                left: fromPercent + &#039;%&#039;,&lt;br /&gt;
                width: firstDelta + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
            barTimerA = setTimeout(function () {&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 540ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: &#039;100%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 260);&lt;br /&gt;
&lt;br /&gt;
            barTimerB = setTimeout(function () {&lt;br /&gt;
                $fill.css({ transition: &#039;none&#039;, width: &#039;0%&#039; });&lt;br /&gt;
                $gain.css({ transition: &#039;none&#039;, opacity: toPercent &amp;gt; 0 ? 1 : 0, left: &#039;0%&#039;, width: toPercent + &#039;%&#039; });&lt;br /&gt;
&lt;br /&gt;
                if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
                $fill.css({&lt;br /&gt;
                    transition: &#039;width 460ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                    width: toPercent + &#039;%&#039;&lt;br /&gt;
                });&lt;br /&gt;
            }, 860);&lt;br /&gt;
&lt;br /&gt;
            barTimerC = setTimeout(function () {&lt;br /&gt;
                $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
            }, 1380);&lt;br /&gt;
&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var delta = Math.max(0, toPercent - fromPercent);&lt;br /&gt;
&lt;br /&gt;
        if (delta &amp;lt;= 0.15) {&lt;br /&gt;
            setBarInstant($fill, $gain, toPercent);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $gain.css({&lt;br /&gt;
            transition: &#039;none&#039;,&lt;br /&gt;
            opacity: 1,&lt;br /&gt;
            left: fromPercent + &#039;%&#039;,&lt;br /&gt;
            width: delta + &#039;%&#039;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        if ($fill[0]) $fill[0].offsetHeight;&lt;br /&gt;
&lt;br /&gt;
        barTimerA = setTimeout(function () {&lt;br /&gt;
            $fill.css({&lt;br /&gt;
                transition: &#039;width 560ms cubic-bezier(0.22, 0.7, 0.18, 1)&#039;,&lt;br /&gt;
                width: toPercent + &#039;%&#039;&lt;br /&gt;
            });&lt;br /&gt;
        }, 260);&lt;br /&gt;
&lt;br /&gt;
        barTimerB = setTimeout(function () {&lt;br /&gt;
            $gain.css({ transition: &#039;opacity 180ms ease&#039;, opacity: 0 });&lt;br /&gt;
        }, 940);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function updatePanel(summary, options) {&lt;br /&gt;
        if (!summary) return;&lt;br /&gt;
&lt;br /&gt;
        options = options || {};&lt;br /&gt;
&lt;br /&gt;
        var $panel = ensurePanel();&lt;br /&gt;
        if (!$panel.length) {&lt;br /&gt;
            pendingSummary = $.extend({}, summary);&lt;br /&gt;
            pendingOptions = $.extend({}, options);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var level = summary.level || 1;&lt;br /&gt;
        var totalXp = summary.totalXp || 0;&lt;br /&gt;
        var xpIntoLevel = summary.xpIntoLevel || 0;&lt;br /&gt;
        var xpForNext = summary.xpForNextLevel || 1;&lt;br /&gt;
        var percent = clampPercent(summary.progressPercent);&lt;br /&gt;
        var isMaxLevel = !!summary.isMaxLevel;&lt;br /&gt;
        var dailyXp = summary.dailyXp || 0;&lt;br /&gt;
        var discoveries = summary.discoveryCount || 0;&lt;br /&gt;
        var title = summary.equippedTitle || summary.title || &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        $panel.removeClass(&#039;is-syncing&#039;).toggleClass(&#039;is-max-level&#039;, isMaxLevel).attr(&#039;data-progress-state&#039;, &#039;ready&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-level-label&#039;).text((isMaxLevel ? &#039;MAX &#039; : &#039;LVL &#039;) + level);&lt;br /&gt;
        $panel.find(&#039;.progress-total-xp&#039;).text(totalXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-xp-next&#039;).text(isMaxLevel ? &#039;MAX LEVEL&#039; : (xpIntoLevel + &#039; / &#039; + xpForNext + &#039; TO NEXT&#039;));&lt;br /&gt;
        $panel.find(&#039;.progress-daily-xp&#039;).text(&#039;TODAY &#039; + dailyXp + &#039; XP&#039;);&lt;br /&gt;
        $panel.find(&#039;.progress-discovery-row&#039;).text(&#039;DISCOVERED &#039; + discoveries);&lt;br /&gt;
&lt;br /&gt;
        var $title = $panel.find(&#039;.progress-title-row&#039;);&lt;br /&gt;
        if (title) {&lt;br /&gt;
            $title.text(title).prop(&#039;hidden&#039;, false);&lt;br /&gt;
        } else {&lt;br /&gt;
            $title.text(&#039;&#039;).prop(&#039;hidden&#039;, true);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $fill = $panel.find(&#039;.progress-xp-fill&#039;);&lt;br /&gt;
        var $gain = $panel.find(&#039;.progress-xp-gain&#039;);&lt;br /&gt;
        var animate = !!options.animateGain &amp;amp;&amp;amp; currentSummary &amp;amp;&amp;amp; totalXp &amp;gt; (currentSummary.totalXp || 0);&lt;br /&gt;
&lt;br /&gt;
        if (animate) {&lt;br /&gt;
            animateGain(&lt;br /&gt;
                $fill,&lt;br /&gt;
                $gain,&lt;br /&gt;
                clampPercent(currentSummary.progressPercent),&lt;br /&gt;
                percent,&lt;br /&gt;
                level !== (currentSummary.level || 1)&lt;br /&gt;
            );&lt;br /&gt;
        } else {&lt;br /&gt;
            setBarInstant($fill, $gain, percent);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        currentSummary = $.extend({}, summary);&lt;br /&gt;
        pendingSummary = null;&lt;br /&gt;
        pendingOptions = null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function requestSummary() {&lt;br /&gt;
        if (!isLoggedIn()) return;&lt;br /&gt;
        if (summaryRequested) return;&lt;br /&gt;
&lt;br /&gt;
        summaryRequested = true;&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.get({&lt;br /&gt;
                action: &#039;progress_summary&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_summary;&lt;br /&gt;
                if (payload &amp;amp;&amp;amp; payload.available &amp;amp;&amp;amp; payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: false });&lt;br /&gt;
                }&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                summaryRequested = false;&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            summaryRequested = false;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function queueNotifications(items) {&lt;br /&gt;
        if (!items || !items.length) return;&lt;br /&gt;
&lt;br /&gt;
        items.forEach(function (item) {&lt;br /&gt;
            if (!item) return;&lt;br /&gt;
            notificationQueue.push(item);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        showNextNotification();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function notificationText(item) {&lt;br /&gt;
        if (item.type === &#039;xp&#039;) {&lt;br /&gt;
            return &#039;+&#039; + (item.amount || 0) + &#039; XP · &#039; + (item.label || &#039;문서 열람&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;achievement&#039;) {&lt;br /&gt;
            var xp = item.amount ? &#039; · +&#039; + item.amount + &#039; XP&#039; : &#039;&#039;;&lt;br /&gt;
            return &#039;업적 달성 · &#039; + (item.label || &#039;새 업적&#039;) + xp;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (item.type === &#039;level&#039;) {&lt;br /&gt;
            return item.label || &#039;레벨 상승&#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return item.label || &#039;보상 획득&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showNextNotification() {&lt;br /&gt;
        if (notificationActive) return;&lt;br /&gt;
        if (!notificationQueue.length) return;&lt;br /&gt;
&lt;br /&gt;
        notificationActive = true;&lt;br /&gt;
        var item = notificationQueue.shift();&lt;br /&gt;
        var $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!$root.length) {&lt;br /&gt;
            $(&#039;body&#039;).append(&#039;&amp;lt;div id=&amp;quot;progress-toast-root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
            $root = $(&#039;#progress-toast-root&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var $toast = $(&#039;&amp;lt;div class=&amp;quot;progress-toast&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
        $toast.text(notificationText(item));&lt;br /&gt;
        $root.append($toast);&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            $toast.addClass(&#039;is-visible&#039;);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        setTimeout(function () {&lt;br /&gt;
            $toast.removeClass(&#039;is-visible&#039;);&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                $toast.remove();&lt;br /&gt;
                notificationActive = false;&lt;br /&gt;
                showNextNotification();&lt;br /&gt;
            }, 220);&lt;br /&gt;
        }, 2600);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applyPendingSummaryIfPossible() {&lt;br /&gt;
        if (!pendingSummary) return;&lt;br /&gt;
        updatePanel(pendingSummary, pendingOptions || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handlePageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (!isRewardableClientSide()) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var pageId = getPageId();&lt;br /&gt;
        if (handledPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (inFlightPageIds.has(pageId)) {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        inFlightPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
        withApi(function (api) {&lt;br /&gt;
            api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
                action: &#039;progress_view&#039;,&lt;br /&gt;
                format: &#039;json&#039;,&lt;br /&gt;
                formatversion: 2,&lt;br /&gt;
                errorformat: &#039;plaintext&#039;,&lt;br /&gt;
                pageid: pageId&lt;br /&gt;
            }).then(function (data) {&lt;br /&gt;
                var payload = data &amp;amp;&amp;amp; data.progress_view;&lt;br /&gt;
                if (!payload) return;&lt;br /&gt;
&lt;br /&gt;
                handledPageIds.add(pageId);&lt;br /&gt;
&lt;br /&gt;
                var animate = hasXpNotification(payload.notifications);&lt;br /&gt;
&lt;br /&gt;
                if (payload.summary) {&lt;br /&gt;
                    updatePanel(payload.summary, { animateGain: animate });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (payload.notifications &amp;amp;&amp;amp; payload.notifications.length) {&lt;br /&gt;
                    queueNotifications(payload.notifications);&lt;br /&gt;
                }&lt;br /&gt;
            }).catch(function () {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }).always(function () {&lt;br /&gt;
                inFlightPageIds.delete(pageId);&lt;br /&gt;
            });&lt;br /&gt;
        }, function () {&lt;br /&gt;
            inFlightPageIds.delete(pageId);&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bindVisibilitySync() {&lt;br /&gt;
        if (visibilityBound) return;&lt;br /&gt;
        visibilityBound = true;&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&#039;visibilitychange&#039;, function () {&lt;br /&gt;
            if (document.visibilityState === &#039;visible&#039;) {&lt;br /&gt;
                requestSummary();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function bootProgressSystem(reason) {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        if (isRewardableClientSide()) {&lt;br /&gt;
            handlePageView();&lt;br /&gt;
        } else {&lt;br /&gt;
            requestSummary();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleSpaPageView() {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
&lt;br /&gt;
        requestAnimationFrame(function () {&lt;br /&gt;
            setTimeout(function () {&lt;br /&gt;
                handlePageView();&lt;br /&gt;
            }, 80);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function applySummary(summary, options) {&lt;br /&gt;
        updatePanel(summary, options || { animateGain: false });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    window.ProgressSystemWebUi = {&lt;br /&gt;
        boot: bootProgressSystem,&lt;br /&gt;
        requestSummary: requestSummary,&lt;br /&gt;
        applySummary: applySummary,&lt;br /&gt;
        handlePageView: handlePageView,&lt;br /&gt;
        handleSpaPageView: handleSpaPageView,&lt;br /&gt;
        ensurePanel: ensurePanel&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        bindVisibilitySync();&lt;br /&gt;
        bootProgressSystem(&#039;documentReady&#039;);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    mw.hook(&#039;wikipage.content&#039;).add(function () {&lt;br /&gt;
        ensurePanel();&lt;br /&gt;
        applyPendingSummaryIfPossible();&lt;br /&gt;
    });&lt;br /&gt;
})(mediaWiki, jQuery);&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
	<entry>
		<id>https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2436</id>
		<title>미디어위키:Layout.css</title>
		<link rel="alternate" type="text/html" href="https://clbiwiki.com/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Layout.css&amp;diff=2436"/>
		<updated>2026-06-01T20:36:11Z</updated>

		<summary type="html">&lt;p&gt;Nxdsxn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* =========================================&lt;br /&gt;
COASTLINE: BLACK ICE - Layout&lt;br /&gt;
Core page shell / top nav / sidebars&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
설계 목적&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
이 파일은 MediaWiki/Liberty 스킨 위에 올라가는 기본 레이아웃 뼈대를 담당한다.&lt;br /&gt;
&lt;br /&gt;
담당 범위:&lt;br /&gt;
- 기본 Liberty 네비 숨김&lt;br /&gt;
- 본문 컨테이너 폭과 배치&lt;br /&gt;
- 본문 컨테이너 외곽 테마&lt;br /&gt;
- 상단 네비바&lt;br /&gt;
- 좌우 사이드바&lt;br /&gt;
- 유저 박스와 사이드 링크 버튼&lt;br /&gt;
- 하단 푸터&lt;br /&gt;
&lt;br /&gt;
현재 디자인 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
1. 전체 컨테이너는 각진 금속 패널로 처리한다.&lt;br /&gt;
2. radius는 사용하지 않는다.&lt;br /&gt;
3. 본문 컨테이너 표면은 #171717을 기준으로 한다.&lt;br /&gt;
4. 상단 네비바와 좌우 사이드바도 같은 장치 계열로 맞춘다.&lt;br /&gt;
5. 상단은 밝게, 좌우는 중간, 하단은 어둡게 잡는 north-light rule을 사용한다.&lt;br /&gt;
6. 보라색 강조색(#854369, #d45aa2) 중심의 이전 테마는 제거한다.&lt;br /&gt;
7. 공사선 모티프는 이 파일에서 쓰지 않는다.&lt;br /&gt;
   공사선은 프로젝트 트래커, 제작 로그, 정비 알림처럼&lt;br /&gt;
   &amp;quot;우리가 만들고 있음&amp;quot;이 전면에 오는 곳에서만 사용한다.&lt;br /&gt;
&lt;br /&gt;
주의:&lt;br /&gt;
- 대문 내부 전용 구성은 MediaWiki:MainPage.css가 담당한다.&lt;br /&gt;
- 카테고리 SVG 네비는 MediaWiki:CategoryNav.js + MainPage.css가 담당한다.&lt;br /&gt;
- 언어 다이얼은 이 파일의 좌측 사이드바 언어 선택기 블록이 담당한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
0. 공통 색상 메모&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
주요 표면:&lt;br /&gt;
#080808 : 깊은 내부 우물 / 화면 내부&lt;br /&gt;
#101010 : 기본 프레임&lt;br /&gt;
#141414 : 약간 밝은 패널 표면&lt;br /&gt;
#171717 : 본문 컨테이너 / 상단 네비 / 사이드 장치 표면&lt;br /&gt;
#1d1d1d : 타이틀바 / 활성 표면&lt;br /&gt;
#252525 : 호버 표면&lt;br /&gt;
&lt;br /&gt;
주요 테두리:&lt;br /&gt;
#555555 : 상단광&lt;br /&gt;
#2b2b2b : 좌우 중간 테두리&lt;br /&gt;
#050505 : 하단암 / 깊은 구분선&lt;br /&gt;
#202020 : 내부 약한 구분선&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
1. Liberty 기본 요소 정리&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#liberty-bottombtn {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
a[accesskey=&amp;quot;t&amp;quot;] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.Liberty .nav-wrapper {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-sidebar {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
2. 전체 배치&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
:root {&lt;br /&gt;
--layout-shell-w:1880px;&lt;br /&gt;
--layout-side-w:230px;&lt;br /&gt;
--layout-gap:8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비와 본문 행의 세로 간격도 좌우 사이드바 간격과 같은 값을 사용한다. */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
overflow-x:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
min-width:calc(var(--layout-shell-w) + 32px) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap,&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.content-wrapper {&lt;br /&gt;
margin:var(--layout-gap) auto 0 !important;&lt;br /&gt;
padding:0 0 16px 0 !important;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:var(--layout-side-w) minmax(0, 1fr) var(--layout-side-w) !important;&lt;br /&gt;
gap:var(--layout-gap) !important;&lt;br /&gt;
align-items:start !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar {&lt;br /&gt;
grid-column:1;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container-fluid.liberty-content {&lt;br /&gt;
grid-column:2;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
padding-bottom:0 !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
flex:none !important;&lt;br /&gt;
width:auto !important;&lt;br /&gt;
max-width:none !important;&lt;br /&gt;
min-width:0 !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
grid-column:3;&lt;br /&gt;
grid-row:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 줌/축소 화면에서도 좌우 사이드바를 문서 폭에 포함시키기 위해&lt;br /&gt;
   사이드바 숨김 반응형 규칙은 제거한다. */&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
3. 본문 컨테이너&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main,&lt;br /&gt;
.Liberty .content-wrapper .liberty-content .liberty-content-main,&lt;br /&gt;
.liberty-content.content-tools-hidden .liberty-content-main {&lt;br /&gt;
background:#1d1d1d !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.012),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.38) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-main .mw-parser-output {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content {&lt;br /&gt;
border:none !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4. 본문 헤더&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header {&lt;br /&gt;
background:transparent !important;&lt;br /&gt;
box-shadow:none !important;&lt;br /&gt;
border:none !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
justify-content:space-between !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
height:auto !important;&lt;br /&gt;
min-height:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .content-tools {&lt;br /&gt;
order:2 !important;&lt;br /&gt;
flex-shrink:0 !important;&lt;br /&gt;
padding-top:0 !important;&lt;br /&gt;
padding-right:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .title {&lt;br /&gt;
order:1 !important;&lt;br /&gt;
flex:1 !important;&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:flex-end !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header h1 {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.liberty-content-header .contentSub {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
4-A. MediaWiki CSS/JS 문서 인디케이터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator-row {&lt;br /&gt;
margin:0 0 8px 0;&lt;br /&gt;
padding:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
justify-content:flex-end;&lt;br /&gt;
align-items:flex-start;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-indicator {&lt;br /&gt;
min-width:320px;&lt;br /&gt;
max-width:min(56%, 860px);&lt;br /&gt;
padding:10px 14px 12px;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.012),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.38) !important;&lt;br /&gt;
background-image:linear-gradient(to bottom, rgba(255,255,255,0.020), rgba(0,0,0,0.08));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
justify-content:flex-end;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
margin:0 0 6px 0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.08em;&lt;br /&gt;
text-transform:uppercase;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-label {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-type {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
background:#0d0d0d;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-system-doc-title {&lt;br /&gt;
display:block;&lt;br /&gt;
text-align:right;&lt;br /&gt;
font-size:34px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
font-weight:900;&lt;br /&gt;
letter-spacing:0.01em;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
text-shadow:0 1px 0 rgba(0,0,0,0.78);&lt;br /&gt;
word-break:break-word;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.clbi-system-doc-page .liberty-content-header,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-main::after,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-namespace,&lt;br /&gt;
body.clbi-system-doc-page .mw-page-title-separator,&lt;br /&gt;
body.clbi-system-doc-page #firstHeading,&lt;br /&gt;
body.clbi-system-doc-page .mw-first-heading {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
5. 페이지 전환 피드백&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
body::after {&lt;br /&gt;
content:&#039;&#039;;&lt;br /&gt;
position:fixed;&lt;br /&gt;
inset:0;&lt;br /&gt;
background:rgba(0,0,0,0);&lt;br /&gt;
transition:background 0.2s ease, opacity 0.2s ease;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
z-index:99999;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
body.page-loading::after {&lt;br /&gt;
background:rgba(0,0,0,0.5);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
6. 좌우 사이드바 공통&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-left-sidebar,&lt;br /&gt;
#clbi-right-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:230px;&lt;br /&gt;
z-index:1000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:8px;&lt;br /&gt;
padding:0;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
align-self:flex-start;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-box,&lt;br /&gt;
.clbi-right-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
padding:0 8px 8px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010,&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-title,&lt;br /&gt;
.clbi-right-title {&lt;br /&gt;
min-height:34px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-content,&lt;br /&gt;
.clbi-right-content {&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:8px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
line-height:1.65;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a,&lt;br /&gt;
.clbi-left-content a {&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-right-content a:not(.clbi-user-btn):hover,&lt;br /&gt;
.clbi-left-content a:not(.clbi-user-btn):hover {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
7. 유저 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.profile-card-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar-wrap,&lt;br /&gt;
#clbi-user-avatar-wrap.profile-identity-panel {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:block;&lt;br /&gt;
min-height:180px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:none;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:50%;&lt;br /&gt;
transform:translate(-50%, -50%);&lt;br /&gt;
width:104px;&lt;br /&gt;
height:104px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#202020&lt;br /&gt;
#101010&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
right:7px;&lt;br /&gt;
top:7px;&lt;br /&gt;
height:1px;&lt;br /&gt;
background:rgba(255,255,255,0.026);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-avatar-stage::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 0 0 rgba(255,255,255,0.006),&lt;br /&gt;
inset -1px 0 0 rgba(0,0,0,0.16);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-avatar {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
width:90px;&lt;br /&gt;
height:90px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.012);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row,&lt;br /&gt;
#clbi-user-name-row.profile-name-row {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:8px;&lt;br /&gt;
right:8px;&lt;br /&gt;
top:calc(50% + 52px);&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:auto;&lt;br /&gt;
margin:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
text-align:center;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row #clbi-user-name {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
margin-top:0;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-user-name-row.profile-name-row-guest #clbi-user-name {&lt;br /&gt;
max-width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
fill:none;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-svg-nav-icon .profile-svg {&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-icon .profile-svg {&lt;br /&gt;
width:15px;&lt;br /&gt;
height:15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-icon,&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-icon {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-icon {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-icon {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-actions {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(3, minmax(0, 1fr));&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin:0 0 8px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
z-index:2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:100%;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
min-height:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%);&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:currentColor;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-tip {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-quick-btn:hover .profile-quick-tip,&lt;br /&gt;
.profile-quick-btn:focus-visible .profile-quick-tip {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9. 유저 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-grid {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:1fr;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-divider {&lt;br /&gt;
height:1px;&lt;br /&gt;
margin:9px 7px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 1px 0 rgba(255,255,255,0.018);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0 7px 7px;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
grid-template-columns:15px minmax(0,1fr) 12px !important;&lt;br /&gt;
column-gap:7px !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:stretch !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
min-height:26px !important;&lt;br /&gt;
height:26px !important;&lt;br /&gt;
margin:0 0 4px !important;&lt;br /&gt;
padding:0 7px !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #141414 0%, #101010 54%, #0c0c0c 100%) !important;&lt;br /&gt;
border:1px solid !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-align:left !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040) !important;&lt;br /&gt;
overflow:hidden !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:last-child {&lt;br /&gt;
margin-bottom:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-label {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
top:0;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
justify-self:end;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #1d1d1d 0%, #171717 54%, #101010 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#444444&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.060),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:hover .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn:active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #0b0b0b 0%, #101010 55%, #171717 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#050505&lt;br /&gt;
#202020&lt;br /&gt;
#333333&lt;br /&gt;
#202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 1px 1px 3px rgba(0,0,0,0.82),&lt;br /&gt;
inset -1px -1px 0 rgba(255,255,255,0.035) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout {&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#3f3f3f&lt;br /&gt;
#2a2020&lt;br /&gt;
#181010&lt;br /&gt;
#2a2020 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout .profile-action-arrow {&lt;br /&gt;
color:#8b5f59;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #241615 0%, #1b1110 56%, #100908 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#6a3933&lt;br /&gt;
#3f2623&lt;br /&gt;
#181010&lt;br /&gt;
#3f2623 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn-logout:hover .profile-action-arrow {&lt;br /&gt;
color:#e0a199;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, #242424 0%, #1d1d1d 55%, #141414 100%) !important;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.070),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.022) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-action-box .clbi-user-btn.clbi-user-btn-active .profile-action-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 기본 유저 버튼: 프로필 액션 박스 밖에서는 기존 사이드 버튼 문법 유지 */&lt;br /&gt;
.clbi-user-btn {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
height:24px !important;&lt;br /&gt;
padding:0 6px !important;&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
border-radius:0 !important;&lt;br /&gt;
font-size:11px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-align:center !important;&lt;br /&gt;
background:#141414 !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65) !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn:hover {&lt;br /&gt;
background:#202020 !important;&lt;br /&gt;
border-color:#333333 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout {&lt;br /&gt;
border-color:#3f2623 !important;&lt;br /&gt;
color:#c88a80 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn-logout:hover {&lt;br /&gt;
background:#1b1110 !important;&lt;br /&gt;
border-color:#6a3933 !important;&lt;br /&gt;
color:#e0a199 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-user-btn.clbi-user-btn-active {&lt;br /&gt;
background:#242424 !important;&lt;br /&gt;
border-color:#555555 !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.055),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.75) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.4 우측 광고판 Ad(not really)&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title {&lt;br /&gt;
justify-content:flex-start;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
gap:4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-text {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:4px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-main,&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-title-note {&lt;br /&gt;
opacity:.20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-body {&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess {&lt;br /&gt;
position:relative;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
padding:8px;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(145deg, #050505 0%, #090909 45%, #030303 100%);&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#202020 #101010 #050505 #101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 9px 18px rgba(0,0,0,0.96),&lt;br /&gt;
inset 0 -2px 3px rgba(255,255,255,0.024),&lt;br /&gt;
inset 7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
inset -7px 0 16px rgba(0,0,0,0.88),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.018);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-recess::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.10;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08) 0%, transparent 20%, transparent 100%),&lt;br /&gt;
linear-gradient(to right, rgba(255,255,255,0.04) 0%, transparent 22%, transparent 100%);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:352px;&lt;br /&gt;
min-height:352px;&lt;br /&gt;
display:block;&lt;br /&gt;
line-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#050505;&lt;br /&gt;
border:1px solid #060606;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 16px rgba(0,0,0,0.90),&lt;br /&gt;
inset 0 0 38px rgba(0,0,0,0.74),&lt;br /&gt;
0 0 0 1px rgba(255,255,255,0.026);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image {&lt;br /&gt;
border:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-base {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:3;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.84)&lt;br /&gt;
contrast(1.08)&lt;br /&gt;
saturate(0.90);&lt;br /&gt;
transform:none;&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom,&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:100%;&lt;br /&gt;
max-width:none;&lt;br /&gt;
max-height:none;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center center;&lt;br /&gt;
border:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-image-bloom {&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.36;&lt;br /&gt;
mix-blend-mode:normal;&lt;br /&gt;
filter:&lt;br /&gt;
blur(7px)&lt;br /&gt;
brightness(0.92)&lt;br /&gt;
contrast(1.02)&lt;br /&gt;
saturate(1.04);&lt;br /&gt;
transform:scale(1.015);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice {&lt;br /&gt;
z-index:5;&lt;br /&gt;
opacity:0;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
filter:&lt;br /&gt;
brightness(0.96)&lt;br /&gt;
contrast(1.18)&lt;br /&gt;
saturate(0.82);&lt;br /&gt;
transform:scale(1.035);&lt;br /&gt;
transform-origin:center center;&lt;br /&gt;
will-change:transform, opacity, clip-path, filter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-a {&lt;br /&gt;
animation:right-billboard-slice-tear-a 4.7s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-b {&lt;br /&gt;
animation:right-billboard-slice-tear-b 6.1s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice-c {&lt;br /&gt;
animation:right-billboard-slice-tear-c 7.4s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:20;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
border-radius:7px / 13px;&lt;br /&gt;
background:&lt;br /&gt;
radial-gradient(&lt;br /&gt;
ellipse at 50% 50%,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
transparent 60%,&lt;br /&gt;
rgba(0,0,0,0.18) 78%,&lt;br /&gt;
rgba(0,0,0,0.46) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(0,0,0,0.18) 0%,&lt;br /&gt;
transparent 15%,&lt;br /&gt;
transparent 82%,&lt;br /&gt;
rgba(0,0,0,0.26) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
rgba(0,0,0,0.20) 0%,&lt;br /&gt;
transparent 9%,&lt;br /&gt;
transparent 91%,&lt;br /&gt;
rgba(0,0,0,0.20) 100%&lt;br /&gt;
),&lt;br /&gt;
linear-gradient(&lt;br /&gt;
105deg,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.030) 18%,&lt;br /&gt;
transparent 38%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 0 20px rgba(255,255,255,0.018),&lt;br /&gt;
inset 0 0 48px rgba(0,0,0,0.56);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-screen::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:-70px 0;&lt;br /&gt;
z-index:21;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:.20;&lt;br /&gt;
background:&lt;br /&gt;
repeating-linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
rgba(255,255,255,0.080) 0px,&lt;br /&gt;
rgba(255,255,255,0.080) 1px,&lt;br /&gt;
transparent 2px,&lt;br /&gt;
transparent 5px&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-scanlines-up 7s linear infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-glitch {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:22;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to bottom,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(255,255,255,0.12) 48%,&lt;br /&gt;
rgba(212,90,162,0.14) 50%,&lt;br /&gt;
rgba(90,120,255,0.08) 52%,&lt;br /&gt;
transparent 56%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-glitch-band 8.2s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:23;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(&lt;br /&gt;
to right,&lt;br /&gt;
transparent 0%,&lt;br /&gt;
rgba(120,180,255,0.07) 10%,&lt;br /&gt;
rgba(255,255,255,0.11) 48%,&lt;br /&gt;
rgba(212,90,162,0.08) 78%,&lt;br /&gt;
transparent 100%&lt;br /&gt;
);&lt;br /&gt;
mix-blend-mode:screen;&lt;br /&gt;
animation:right-billboard-soft-horizontal-tear 5.6s steps(1,end) infinite;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty {&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:8;&lt;br /&gt;
display:none;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
min-height:0;&lt;br /&gt;
background:#050505;&lt;br /&gt;
color:#626262;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-screen {&lt;br /&gt;
min-height:352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-empty {&lt;br /&gt;
display:flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-image,&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-slice {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-main {&lt;br /&gt;
display:block;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:.7px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-empty-sub {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
color:#626262;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:calc(100% + 4px);&lt;br /&gt;
z-index:40;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:0;&lt;br /&gt;
width:max-content;&lt;br /&gt;
min-width:42px;&lt;br /&gt;
max-width:calc(100% - 8px);&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:3px 6px 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#101010;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:center;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.035),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 4px 10px rgba(0,0,0,0.44);&lt;br /&gt;
visibility:hidden;&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translate(-50%, -1px);&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box:hover .right-billboard-caption,&lt;br /&gt;
.right-billboard-box:focus-within .right-billboard-caption {&lt;br /&gt;
visibility:visible;&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translate(-50%, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line {&lt;br /&gt;
display:block;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-caption-line.is-gap {&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:10px;&lt;br /&gt;
font-size:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-box.is-empty .right-billboard-caption {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-scanlines-up {&lt;br /&gt;
from { transform:translateY(0); }&lt;br /&gt;
to { transform:translateY(-70px); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-a {&lt;br /&gt;
0%, 11%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
12% { opacity:.34; transform:translateX(-10px) scale(1.035); clip-path:inset(17% 0 78% 0); }&lt;br /&gt;
13% { opacity:.20; transform:translateX(7px) scale(1.035); clip-path:inset(18% 0 77% 0); filter:hue-rotate(-8deg); }&lt;br /&gt;
14% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
63% { opacity:.26; transform:translateX(6px) scale(1.035); clip-path:inset(24% 0 70% 0); }&lt;br /&gt;
64% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-b {&lt;br /&gt;
0%, 37%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
38% { opacity:.36; transform:translateX(12px) scale(1.035); clip-path:inset(43% 0 50% 0); }&lt;br /&gt;
39% { opacity:.22; transform:translateX(-8px) scale(1.035); clip-path:inset(45% 0 48% 0); filter:hue-rotate(10deg) brightness(1.08); }&lt;br /&gt;
40% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
78% { opacity:.30; transform:translateX(-11px) scale(1.035); clip-path:inset(51% 0 43% 0); }&lt;br /&gt;
79% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-slice-tear-c {&lt;br /&gt;
0%, 21%, 100% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
22% { opacity:.24; transform:translateX(-14px) scale(1.035); clip-path:inset(67% 0 25% 0); }&lt;br /&gt;
23% { opacity:.16; transform:translateX(10px) scale(1.035); clip-path:inset(68% 0 23% 0); filter:contrast(1.25) brightness(1.06); }&lt;br /&gt;
24% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
91% { opacity:.30; transform:translateX(10px) scale(1.035); clip-path:inset(73% 0 18% 0); }&lt;br /&gt;
92% { opacity:0; transform:translateX(0) scale(1.035); clip-path:inset(0 0 100% 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-glitch-band {&lt;br /&gt;
0%, 52%, 100% { opacity:0; transform:translateY(80%); }&lt;br /&gt;
53% { opacity:.38; transform:translateY(36%); }&lt;br /&gt;
54% { opacity:.14; transform:translateY(20%) skewX(-1deg); }&lt;br /&gt;
55% { opacity:0; transform:translateY(-20%); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes right-billboard-soft-horizontal-tear {&lt;br /&gt;
0%, 68%, 100% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
69% { opacity:.28; transform:translateX(-10px); clip-path:inset(34% 0 58% 0); }&lt;br /&gt;
70% { opacity:.16; transform:translateX(8px); clip-path:inset(37% 0 55% 0); }&lt;br /&gt;
71% { opacity:0; transform:translateX(0); clip-path:inset(0 0 0 0); }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media (prefers-reduced-motion: reduce) {&lt;br /&gt;
.right-billboard-slice-a,&lt;br /&gt;
.right-billboard-slice-b,&lt;br /&gt;
.right-billboard-slice-c,&lt;br /&gt;
.right-billboard-screen::after,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
animation:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.right-billboard-slice,&lt;br /&gt;
.right-billboard-glitch,&lt;br /&gt;
.right-billboard-tear {&lt;br /&gt;
opacity:0 !important;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.45 우측 사이트 정보&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar {&lt;br /&gt;
position:relative;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title {&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title &amp;gt; span:first-child {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-title-meta {&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
letter-spacing:.55px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-content {&lt;br /&gt;
line-height:1.4;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-list {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:minmax(0,1fr) 18px;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
height:24px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
line-height:1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:last-child {&lt;br /&gt;
border-bottom:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row a {&lt;br /&gt;
display:block;&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover a {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-mark {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-align:right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .policy-row:hover .policy-mark {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-strip {&lt;br /&gt;
display:grid;&lt;br /&gt;
grid-template-columns:repeat(4,1fr);&lt;br /&gt;
gap:4px;&lt;br /&gt;
margin-top:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
aspect-ratio:1 / 1;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a {&lt;br /&gt;
display:flex !important;&lt;br /&gt;
align-items:center !important;&lt;br /&gt;
justify-content:center !important;&lt;br /&gt;
width:100% !important;&lt;br /&gt;
height:100% !important;&lt;br /&gt;
border:1px solid #202020 !important;&lt;br /&gt;
background:#111111 !important;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:10px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
line-height:1 !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.site-info-sidebar .social-icon a:hover {&lt;br /&gt;
background:#1c1c1c !important;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
border-color:#3a3a3a !important;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
9.5 왼쪽 언어 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
z-index:1002;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 언어 박스 내부 라벨 패널 표준&lt;br /&gt;
   - 외곽 검은 선은 만들지 않는다.&lt;br /&gt;
   - 광원과 그림자는 사이드 프레임과 같은 한 세트(#555555 / #101010)를 사용한다.&lt;br /&gt;
   - 텍스트가 내부선에 붙지 않도록 상하 3px 패딩을 기본값으로 둔다. */&lt;br /&gt;
.clbi-left-lang-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-language {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-language-icon .profile-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-left-lang-box .clbi-left-content {&lt;br /&gt;
padding:2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector,&lt;br /&gt;
.sidebar-lang-dial {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
padding:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
user-select:none;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
outline:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-dial-stage {&lt;br /&gt;
--lang-fan-half:99px;&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:146px;&lt;br /&gt;
margin:0;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:2px;&lt;br /&gt;
z-index:2;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
overflow:visible;&lt;br /&gt;
touch-action:pan-y;&lt;br /&gt;
cursor:grab;&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan:active,&lt;br /&gt;
.sidebar-lang-selector.is-dragging .sidebar-lang-fan,&lt;br /&gt;
.sidebar-lang-selector.is-spinning .sidebar-lang-fan {&lt;br /&gt;
cursor:grabbing;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fan-svg {&lt;br /&gt;
display:block;&lt;br /&gt;
width:198px;&lt;br /&gt;
height:147px;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
shape-rendering:geometricPrecision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-wheel-rotor {&lt;br /&gt;
transform-origin:101px 119px;&lt;br /&gt;
transform-box:view-box;&lt;br /&gt;
will-change:transform;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-selector.is-snapping .sidebar-lang-wheel-rotor {&lt;br /&gt;
transition:transform 210ms cubic-bezier(.17,.84,.22,1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-shell {&lt;br /&gt;
fill:#080808;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft,&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#000000;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-soft {&lt;br /&gt;
stroke-width:16;&lt;br /&gt;
opacity:.34;&lt;br /&gt;
filter:url(#clbi-sidebar-language-shadow-blur);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-inner-shadow-hard {&lt;br /&gt;
stroke-width:6;&lt;br /&gt;
opacity:.22;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group {&lt;br /&gt;
pointer-events:auto;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group:hover .sidebar-lang-sector,&lt;br /&gt;
.sidebar-lang-sector:hover,&lt;br /&gt;
.sidebar-lang-sector.is-center,&lt;br /&gt;
.sidebar-lang-sector.is-far {&lt;br /&gt;
fill:#101010;&lt;br /&gt;
stroke:#181818;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-label {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
text-anchor:middle;&lt;br /&gt;
dominant-baseline:middle;&lt;br /&gt;
paint-order:stroke;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:2px;&lt;br /&gt;
stroke-linejoin:round;&lt;br /&gt;
font-size:9px !important;&lt;br /&gt;
font-weight:700 !important;&lt;br /&gt;
letter-spacing:.15px;&lt;br /&gt;
fill:#c8c8c8;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-name {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-center .sidebar-lang-sector-name,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-label,&lt;br /&gt;
.sidebar-lang-sector-group.is-neighbor .sidebar-lang-sector-name {&lt;br /&gt;
fill:inherit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth,&lt;br /&gt;
.sidebar-lang-fixed-focus,&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-depth {&lt;br /&gt;
fill:url(#clbi-sidebar-language-fixed-depth);&lt;br /&gt;
opacity:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-focus {&lt;br /&gt;
fill:rgba(255,255,255,0.020);&lt;br /&gt;
stroke:rgba(255,255,255,0.020);&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-rim {&lt;br /&gt;
fill:none;&lt;br /&gt;
stroke:#202020;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-fixed-pointer {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
clip-path:url(#clbi-sidebar-language-fan-clip);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-line {&lt;br /&gt;
stroke:#b94a3c;&lt;br /&gt;
stroke-width:2;&lt;br /&gt;
stroke-linecap:square;&lt;br /&gt;
opacity:.94;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-pointer-triangle {&lt;br /&gt;
fill:#b94a3c;&lt;br /&gt;
stroke:#050505;&lt;br /&gt;
stroke-width:1;&lt;br /&gt;
stroke-linejoin:miter;&lt;br /&gt;
vector-effect:non-scaling-stroke;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:93px;&lt;br /&gt;
z-index:5;&lt;br /&gt;
width:52px;&lt;br /&gt;
height:53px;&lt;br /&gt;
margin:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
border-radius:26px 26px 0 0;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply::before,&lt;br /&gt;
.sidebar-lang-apply::after {&lt;br /&gt;
content:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:hover {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply:active {&lt;br /&gt;
transform:translateX(-50%) translateY(1px);&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply.is-disabled,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:hover,&lt;br /&gt;
.sidebar-lang-apply.is-disabled:active {&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#626262;&lt;br /&gt;
cursor:default;&lt;br /&gt;
opacity:1;&lt;br /&gt;
box-shadow:&lt;br /&gt;
0 0 0 2px #080808,&lt;br /&gt;
0 0 0 4px #1d1d1d,&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-apply-mark {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:block;&lt;br /&gt;
font-size:20px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
transform:translateY(3px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-panel {&lt;br /&gt;
position:absolute;&lt;br /&gt;
bottom:5px;&lt;br /&gt;
width:69px;&lt;br /&gt;
height:25px;&lt;br /&gt;
z-index:4;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
padding:3px 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
text-align:center;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-left {&lt;br /&gt;
left:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right {&lt;br /&gt;
right:calc(50% - var(--lang-fan-half));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-value {&lt;br /&gt;
display:block;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-width:0;&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
font-family:inherit !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right .sidebar-lang-status-value {&lt;br /&gt;
font-size:8px;&lt;br /&gt;
letter-spacing:.12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-ready .sidebar-lang-status-value {&lt;br /&gt;
color:#f0f0f0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-current .sidebar-lang-status-value {&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sidebar-lang-status-right.is-locked .sidebar-lang-status-value {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
10. 왼쪽 뉴스 박스&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-left-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
min-height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 박스 타이틀은 언어 박스에서 확정한 내부 라벨 패널 표준을 따른다.&lt;br /&gt;
   - 컨테이너 상단 기준: 위 4px, 아래 3px&lt;br /&gt;
   - 외곽 검은 선 없음&lt;br /&gt;
   - 광원/그림자는 #555555 / #101010 한 세트만 사용 */&lt;br /&gt;
.clbi-left-news-box &amp;gt; .clbi-left-title {&lt;br /&gt;
min-height:0;&lt;br /&gt;
height:auto;&lt;br /&gt;
margin:4px 0 3px;&lt;br /&gt;
padding:3px 7px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-title-left-news {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:100%;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon,&lt;br /&gt;
.news-title-icon.sidebar-title-svg {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
flex:0 0 16px;&lt;br /&gt;
vertical-align:middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-title-icon .profile-svg,&lt;br /&gt;
.news-title-icon.sidebar-title-svg .profile-svg {&lt;br /&gt;
width:16px;&lt;br /&gt;
height:16px;&lt;br /&gt;
display:block;&lt;br /&gt;
stroke:currentColor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 뉴스 컨텐츠 슬롯은 언어 박스와 같은 3px 내부 기준을 따른다. */&lt;br /&gt;
.clbi-news-box {&lt;br /&gt;
position:relative;&lt;br /&gt;
padding:3px !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
background:#080808;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 타이틀: 컨텐츠 슬롯 내부의 라벨 패널 */&lt;br /&gt;
.news-feed-title {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:auto;&lt;br /&gt;
min-height:22px;&lt;br /&gt;
margin:0 0 2px 0;&lt;br /&gt;
padding:3px 7px 3px 16px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.55px;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-feed-title::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:7px;&lt;br /&gt;
top:50%;&lt;br /&gt;
width:4px;&lt;br /&gt;
height:8px;&lt;br /&gt;
transform:translateY(-50%);&lt;br /&gt;
background:#c8c8c8;&lt;br /&gt;
box-shadow:1px 1px 0 #050505;&lt;br /&gt;
opacity:0.85;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-changelog-title {&lt;br /&gt;
margin-top:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-left-news-recent-title {&lt;br /&gt;
margin-top:2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 섹션 본체는 별도 프레임을 만들지 않는 배치 래퍼다. */&lt;br /&gt;
.news-left-changelog-feed,&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
background:transparent;&lt;br /&gt;
border:0;&lt;br /&gt;
box-shadow:none;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-changelog-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-left-recent-feed {&lt;br /&gt;
padding:0;&lt;br /&gt;
color:#9a9a9a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1.55;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-divider {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 버튼형 항목: 단색 표면 + 최외곽 검은 선 + 동일 광원 세트 */&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:grid !important;&lt;br /&gt;
align-items:center;&lt;br /&gt;
gap:6px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item {&lt;br /&gt;
grid-template-columns:minmax(0,1fr) auto;&lt;br /&gt;
min-height:26px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item {&lt;br /&gt;
grid-template-columns:28px minmax(0,1fr) auto;&lt;br /&gt;
min-height:36px;&lt;br /&gt;
margin:0 0 2px;&lt;br /&gt;
padding:4px 6px 4px 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:last-child,&lt;br /&gt;
.news-recent-item:last-child {&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover,&lt;br /&gt;
.news-recent-item:hover {&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:active,&lt;br /&gt;
.news-recent-item:active {&lt;br /&gt;
background:#101010;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-avatar {&lt;br /&gt;
display:block;&lt;br /&gt;
width:24px;&lt;br /&gt;
height:24px;&lt;br /&gt;
object-fit:cover;&lt;br /&gt;
object-position:center;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #050505;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #555555,&lt;br /&gt;
inset -1px 0 0 #555555,&lt;br /&gt;
inset 1px 0 0 #101010,&lt;br /&gt;
inset 0 -1px 0 #101010;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-avatar {&lt;br /&gt;
border-color:#050505;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-main {&lt;br /&gt;
min-width:0;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap,&lt;br /&gt;
.news-recent-title-wrap {&lt;br /&gt;
min-width:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
-webkit-mask-image:linear-gradient(to right, black 88%, transparent 100%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title-wrap {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-title,&lt;br /&gt;
.news-recent-title {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
max-width:none;&lt;br /&gt;
overflow:visible;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.18;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-title,&lt;br /&gt;
.news-recent-item:hover .news-recent-title {&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-arrow {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
width:12px;&lt;br /&gt;
height:12px;&lt;br /&gt;
margin-left:5px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
vertical-align:-1px;&lt;br /&gt;
flex:0 0 auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-meta {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
min-width:0;&lt;br /&gt;
height:10px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-user {&lt;br /&gt;
display:block !important;&lt;br /&gt;
min-width:0;&lt;br /&gt;
max-width:100%;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
text-overflow:ellipsis;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
color:#7a7a7a !important;&lt;br /&gt;
font-size:8.5px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:hover .news-recent-user {&lt;br /&gt;
color:#b0b0b0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 항목 내부의 작은 상태 버튼: 외곽선 없이 우물 방향 내부선만 사용 */&lt;br /&gt;
.news-post-tag,&lt;br /&gt;
.news-recent-time {&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:16px;&lt;br /&gt;
min-width:34px;&lt;br /&gt;
padding:0 4px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:0;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item:hover .news-post-tag,&lt;br /&gt;
.news-recent-item:hover .news-recent-time {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-recent-item:active .news-recent-time {&lt;br /&gt;
background:#080808;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 #101010,&lt;br /&gt;
inset -1px 0 0 #101010,&lt;br /&gt;
inset 1px 0 0 #555555,&lt;br /&gt;
inset 0 -1px 0 #555555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item * {&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
12. 왼쪽 목차&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#side-toc-box .toc-sidebar-content {&lt;br /&gt;
padding:6px 8px 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
list-style:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li {&lt;br /&gt;
margin:0 !important;&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a {&lt;br /&gt;
display:block !important;&lt;br /&gt;
height:23px;&lt;br /&gt;
line-height:23px;&lt;br /&gt;
padding:0 2px;&lt;br /&gt;
border-bottom:1px solid #202020;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc li:first-child a {&lt;br /&gt;
border-top:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc a:hover {&lt;br /&gt;
background:#101010;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.generated-toc .toc-level-3 a {&lt;br /&gt;
padding-left:12px;&lt;br /&gt;
font-weight:600;&lt;br /&gt;
color:#9f9f9f !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap {&lt;br /&gt;
display:block;&lt;br /&gt;
position:relative;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-text {&lt;br /&gt;
display:inline-block;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.toc-scroll-wrap.is-scrolling::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:0;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:18px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:linear-gradient(to right, transparent, #080808);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
14. 하단 푸터&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
footer,&lt;br /&gt;
.liberty-footer {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
15. 상단 네비게이션 바&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
상단 네비바 공식&lt;br /&gt;
-----------------------------------------&lt;br /&gt;
- 전체는 하나의 각진 조작 패널이다.&lt;br /&gt;
- 탭 하나하나는 독립 버튼 외장보다 패널 내부 구획에 가깝다.&lt;br /&gt;
- radius는 사용하지 않는다.&lt;br /&gt;
- 보라색 테마를 쓰지 않는다.&lt;br /&gt;
- 검색창도 같은 금속 인풋으로 정리한다.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-wrap {&lt;br /&gt;
width:var(--layout-shell-w) !important;&lt;br /&gt;
max-width:var(--layout-shell-w) !important;&lt;br /&gt;
min-width:var(--layout-shell-w) !important;&lt;br /&gt;
margin:0 auto !important;&lt;br /&gt;
padding:var(--layout-gap) 0 0 !important;&lt;br /&gt;
box-sizing:border-box !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#555555&lt;br /&gt;
#2b2b2b&lt;br /&gt;
#050505&lt;br /&gt;
#2b2b2b;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.34);&lt;br /&gt;
margin-bottom:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-main {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
width:100%;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
padding:0 8px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-logo img {&lt;br /&gt;
height:36px;&lt;br /&gt;
width:auto;&lt;br /&gt;
display:block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
16. 상단 네비 탭&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-tabs {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex:1;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:8px;&lt;br /&gt;
width:120px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
padding:0;&lt;br /&gt;
background:transparent;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
border-right:1px solid #202020;&lt;br /&gt;
cursor:pointer;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
border-color 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
user-select:none;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
color:#e2e2e2 !important;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover {&lt;br /&gt;
min-height:38px;&lt;br /&gt;
background:#1d1d1d;&lt;br /&gt;
border-left-color:#333333;&lt;br /&gt;
border-right-color:#333333;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.045),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.65);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
background:#242424;&lt;br /&gt;
border-left-color:#444444;&lt;br /&gt;
border-right-color:#444444;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.050),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.70);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-icon {&lt;br /&gt;
display:block;&lt;br /&gt;
width:22px;&lt;br /&gt;
height:22px;&lt;br /&gt;
object-fit:contain;&lt;br /&gt;
flex:0 0 22px;&lt;br /&gt;
image-rendering:pixelated;&lt;br /&gt;
opacity:0.88;&lt;br /&gt;
align-self:center;&lt;br /&gt;
filter:grayscale(0.18) contrast(1.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-icon,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-icon {&lt;br /&gt;
opacity:1;&lt;br /&gt;
filter:grayscale(0) contrast(1.08);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
17. 언어 버튼&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang {&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
align-items:center;&lt;br /&gt;
width:54px;&lt;br /&gt;
min-height:38px;&lt;br /&gt;
gap:1px;&lt;br /&gt;
padding:4px 0;&lt;br /&gt;
border-left:1px solid transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-code {&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
letter-spacing:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang .clbi-tnav-arrow {&lt;br /&gt;
font-size:9px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
width:8px;&lt;br /&gt;
text-align:center;&lt;br /&gt;
flex-shrink:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang:hover {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-lang-bottom {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
gap:3px;&lt;br /&gt;
line-height:1;&lt;br /&gt;
width:100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-label {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
display:inline-flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
height:22px;&lt;br /&gt;
line-height:22px;&lt;br /&gt;
font-size:13px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-arrow {&lt;br /&gt;
position:relative;&lt;br /&gt;
z-index:1;&lt;br /&gt;
font-size:12px;&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
transition:color 0.12s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item:hover .clbi-tnav-arrow,&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active .clbi-tnav-arrow {&lt;br /&gt;
color:#ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
18. 상단 검색&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-search {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:50%;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
transform:translateX(-50%);&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input {&lt;br /&gt;
width:240px;&lt;br /&gt;
height:26px;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
padding:0 10px;&lt;br /&gt;
border-radius:0;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
outline:none;&lt;br /&gt;
pointer-events:all;&lt;br /&gt;
transition:border-color 0.12s, width 0.2s, background 0.12s;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.55);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-search-input:focus {&lt;br /&gt;
border-color:#555555;&lt;br /&gt;
background:#0c0c0c;&lt;br /&gt;
width:320px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-top-nav-right {&lt;br /&gt;
margin-left:auto;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
border-left:1px solid #202020;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
19. 세계관 펼침 영역&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding {&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:0;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
border-top:0 solid #050505;&lt;br /&gt;
background:#080808;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 180ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding.worldbuilding-open {&lt;br /&gt;
height:38px;&lt;br /&gt;
border-top-width:1px;&lt;br /&gt;
transition:&lt;br /&gt;
height 180ms ease,&lt;br /&gt;
border-top-width 0ms linear 0ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#clbi-sub-worldbuilding-inner {&lt;br /&gt;
height:38px;&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-list {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:stretch;&lt;br /&gt;
flex-wrap:nowrap;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0;&lt;br /&gt;
margin:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item {&lt;br /&gt;
position:relative;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
height:38px;&lt;br /&gt;
padding:0 15px 1px 15px;&lt;br /&gt;
background:transparent;&lt;br /&gt;
color:#c8c8c8 !important;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-decoration:none !important;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
transition:&lt;br /&gt;
background 0.12s,&lt;br /&gt;
color 0.12s,&lt;br /&gt;
box-shadow 0.12s;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item::after {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
top:6px;&lt;br /&gt;
right:0;&lt;br /&gt;
bottom:6px;&lt;br /&gt;
width:1px;&lt;br /&gt;
background:#202020;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:last-child::after {&lt;br /&gt;
display:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-tnav-sub-item:hover {&lt;br /&gt;
background:#151515;&lt;br /&gt;
color:#ffffff !important;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.030),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* 상단 네비: hover/active 인접 경계선 중복 방지 */&lt;br /&gt;
.clbi-top-nav-item:hover + .clbi-top-nav-item.clbi-tnav-active {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.clbi-top-nav-item.clbi-tnav-active + .clbi-top-nav-item:hover {&lt;br /&gt;
border-left-color:transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System UI&lt;br /&gt;
MediaWiki:Layout.css controlled frontend&lt;br /&gt;
========================================= */&lt;br /&gt;
/* =========================================&lt;br /&gt;
Progress System&lt;br /&gt;
========================================= */&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block {&lt;br /&gt;
--xp-base-a:#5f9f68;&lt;br /&gt;
--xp-base-b:#9acb7a;&lt;br /&gt;
--xp-gain-a:#238c84;&lt;br /&gt;
--xp-gain-b:#54c7bb;&lt;br /&gt;
--xp-glow:rgba(35,140,132,0.20);&lt;br /&gt;
position:relative;&lt;br /&gt;
margin:7px 7px 0;&lt;br /&gt;
padding:6px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#080808;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#050505&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.020),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.58);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level {&lt;br /&gt;
--xp-base-a:#b58a3a;&lt;br /&gt;
--xp-base-b:#f0ce75;&lt;br /&gt;
--xp-gain-a:#d9aa42;&lt;br /&gt;
--xp-gain-b:#fff0a8;&lt;br /&gt;
--xp-glow:rgba(224,190,104,0.30);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-level-label {&lt;br /&gt;
color:#f0ce75;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 7px rgba(224,190,104,0.28);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-total-xp {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-bar {&lt;br /&gt;
border-color:#4a3b18;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.62),&lt;br /&gt;
0 0 6px rgba(224,190,104,0.18);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.profile-progress-block.is-max-level .progress-xp-next {&lt;br /&gt;
color:#e0be68;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-panel-fallback-body {&lt;br /&gt;
padding:0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row {&lt;br /&gt;
min-height:16px;&lt;br /&gt;
margin:0 0 6px;&lt;br /&gt;
padding:0 6px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
color:#c8c8c8;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-title-row[hidden] {&lt;br /&gt;
display:none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row,&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:space-between;&lt;br /&gt;
gap:6px;&lt;br /&gt;
min-width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-row {&lt;br /&gt;
margin-bottom:5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-level-label {&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:14px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
letter-spacing:0.2px;&lt;br /&gt;
text-shadow:&lt;br /&gt;
1px 1px 0 #000,&lt;br /&gt;
0 0 5px rgba(154,203,122,0.14);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-total-xp {&lt;br /&gt;
color:#b8c9b4;&lt;br /&gt;
font-size:10px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar {&lt;br /&gt;
position:relative;&lt;br /&gt;
width:100%;&lt;br /&gt;
height:10px;&lt;br /&gt;
margin:0 0 5px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#070707;&lt;br /&gt;
border:1px solid #202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.025),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.60);&lt;br /&gt;
overflow:hidden;&lt;br /&gt;
isolation:isolate;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-bar::before {&lt;br /&gt;
content:&amp;quot;&amp;quot;;&lt;br /&gt;
position:absolute;&lt;br /&gt;
inset:0;&lt;br /&gt;
z-index:4;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
background:&lt;br /&gt;
linear-gradient(to bottom, rgba(255,255,255,0.08), transparent 45%, rgba(0,0,0,0.18));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill,&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
position:absolute;&lt;br /&gt;
left:0;&lt;br /&gt;
top:0;&lt;br /&gt;
bottom:0;&lt;br /&gt;
width:0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-gain {&lt;br /&gt;
z-index:1;&lt;br /&gt;
opacity:0;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-gain-b) 0%, var(--xp-gain-a) 58%, #155c58 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.18),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.46),&lt;br /&gt;
0 0 5px var(--xp-glow);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-fill {&lt;br /&gt;
z-index:2;&lt;br /&gt;
background:linear-gradient(to bottom, var(--xp-base-b) 0%, var(--xp-base-a) 58%, #3f7346 100%);&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.24),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.42);&lt;br /&gt;
transition:width 260ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-sub-row {&lt;br /&gt;
margin-bottom:6px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-xp-next,&lt;br /&gt;
.progress-daily-xp,&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
color:#8a8a8a;&lt;br /&gt;
font-size:9px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-daily-xp {&lt;br /&gt;
white-space:nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-discovery-row {&lt;br /&gt;
height:18px;&lt;br /&gt;
display:flex;&lt;br /&gt;
align-items:center;&lt;br /&gt;
justify-content:center;&lt;br /&gt;
background:#141414;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:&lt;br /&gt;
#333333&lt;br /&gt;
#202020&lt;br /&gt;
#181818&lt;br /&gt;
#202020;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#progress-toast-root {&lt;br /&gt;
position:fixed;&lt;br /&gt;
right:18px;&lt;br /&gt;
bottom:18px;&lt;br /&gt;
z-index:100000;&lt;br /&gt;
display:flex;&lt;br /&gt;
flex-direction:column;&lt;br /&gt;
gap:6px;&lt;br /&gt;
pointer-events:none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast {&lt;br /&gt;
min-width:220px;&lt;br /&gt;
max-width:320px;&lt;br /&gt;
padding:8px 10px;&lt;br /&gt;
box-sizing:border-box;&lt;br /&gt;
background:#171717;&lt;br /&gt;
border:1px solid;&lt;br /&gt;
border-color:#555555 #2b2b2b #050505 #2b2b2b;&lt;br /&gt;
color:#e2e2e2;&lt;br /&gt;
font-size:11px;&lt;br /&gt;
font-weight:700;&lt;br /&gt;
line-height:1.35;&lt;br /&gt;
text-shadow:1px 1px 0 #000;&lt;br /&gt;
box-shadow:&lt;br /&gt;
inset 0 1px 0 rgba(255,255,255,0.040),&lt;br /&gt;
inset 0 -1px 0 rgba(0,0,0,0.72),&lt;br /&gt;
0 6px 18px rgba(0,0,0,0.42);&lt;br /&gt;
opacity:0;&lt;br /&gt;
transform:translateY(8px);&lt;br /&gt;
transition:opacity 160ms ease, transform 160ms ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.progress-toast.is-visible {&lt;br /&gt;
opacity:1;&lt;br /&gt;
transform:translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* -----------------------------------------&lt;br /&gt;
Analog hover normalization&lt;br /&gt;
----------------------------------------- */&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item,&lt;br /&gt;
#clbi-top-nav .clbi-top-nav-item *,&lt;br /&gt;
#clbi-sub-worldbuilding .clbi-tnav-sub-item,&lt;br /&gt;
#clbi-search-btn,&lt;br /&gt;
.clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn,&lt;br /&gt;
.profile-action-box .clbi-user-btn *,&lt;br /&gt;
.profile-quick-btn,&lt;br /&gt;
.profile-quick-btn *,&lt;br /&gt;
.news-post-item,&lt;br /&gt;
.news-post-item *,&lt;br /&gt;
.news-recent-item,&lt;br /&gt;
.news-recent-item *,&lt;br /&gt;
.clbi-left-news-main,&lt;br /&gt;
.clbi-left-news-main *,&lt;br /&gt;
.clbi-link-btn,&lt;br /&gt;
.clbi-link-box ul li a,&lt;br /&gt;
#clbi-playlist-toggle,&lt;br /&gt;
#clbi-notification-toggle {&lt;br /&gt;
transition:none !important;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Nxdsxn</name></author>
	</entry>
</feed>